mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 12:44:21 +00:00
dart2js: Refactoring, documentation, and a few bugfixes in Namer class.
See long doc comment in namer.dart. BUG= R=floitsch@google.com Committed: https://code.google.com/p/dart/source/detail?r=43588 Reverted: https://code.google.com/p/dart/source/detail?r=43590 (to avoid rebase conflicts for people pushing to trunk) Committed: https://code.google.com/p/dart/source/detail?r=43724 Reverted: https://code.google.com/p/dart/source/detail?r=43739 (red bots) Review URL: https://codereview.chromium.org//891673003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44092 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
0f41a29315
commit
96b77b5be9
|
@ -2223,6 +2223,9 @@ bool invariant(Spannable spannable, var condition, {var message: null}) {
|
|||
/// Returns `true` when [s] is private if used as an identifier.
|
||||
bool isPrivateName(String s) => !s.isEmpty && s.codeUnitAt(0) == $_;
|
||||
|
||||
/// Returns `true` when [s] is public if used as an identifier.
|
||||
bool isPublicName(String s) => !isPrivateName(s);
|
||||
|
||||
/// A sink that drains into /dev/null.
|
||||
class NullSink implements EventSink<String> {
|
||||
final String name;
|
||||
|
|
|
@ -547,7 +547,7 @@ class JavaScriptBackend extends Backend {
|
|||
|
||||
String registerOneShotInterceptor(Selector selector) {
|
||||
Set<ClassElement> classes = getInterceptedClassesOn(selector.name);
|
||||
String name = namer.getOneShotInterceptorName(selector, classes);
|
||||
String name = namer.nameForGetOneShotInterceptor(selector, classes);
|
||||
if (!oneShotInterceptors.containsKey(name)) {
|
||||
registerSpecializedGetInterceptor(classes);
|
||||
oneShotInterceptors[name] = selector;
|
||||
|
@ -746,7 +746,7 @@ class JavaScriptBackend extends Backend {
|
|||
}
|
||||
|
||||
void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
|
||||
String name = namer.getInterceptorName(getInterceptorMethod, classes);
|
||||
String name = namer.nameForGetInterceptor(classes);
|
||||
if (classes.contains(jsInterceptorClass)) {
|
||||
// We can't use a specialized [getInterceptorMethod], so we make
|
||||
// sure we emit the one with all checks.
|
||||
|
|
|
@ -270,7 +270,6 @@ class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
|
|||
if (node.target is ConstructorBodyElement) {
|
||||
// A constructor body cannot be overriden or intercepted, so we can
|
||||
// use the short form for this invocation.
|
||||
// TODO(asgerf): prevent name clash between constructor bodies.
|
||||
return js.js('#.#(#)',
|
||||
[visitExpression(node.receiver),
|
||||
glue.instanceMethodName(node.target),
|
||||
|
|
|
@ -108,9 +108,7 @@ class Glue {
|
|||
|
||||
|
||||
String getInterceptorName(Set<ClassElement> interceptedClasses) {
|
||||
return _backend.namer.getInterceptorName(
|
||||
getInterceptorMethod,
|
||||
interceptedClasses);
|
||||
return _backend.namer.nameForGetInterceptor(interceptedClasses);
|
||||
}
|
||||
|
||||
js.Expression getInterceptorLibrary() {
|
||||
|
|
|
@ -250,7 +250,7 @@ class ConstantEmitter
|
|||
@override
|
||||
jsAst.Expression visitType(TypeConstantValue constant, [_]) {
|
||||
DartType type = constant.representedType;
|
||||
String name = namer.getRuntimeTypeName(type.element);
|
||||
String name = namer.runtimeTypeName(type.element);
|
||||
jsAst.Expression typeName = new jsAst.LiteralString("'$name'");
|
||||
return new jsAst.Call(getHelperProperty(backend.getCreateRuntimeType()),
|
||||
[typeName]);
|
||||
|
|
|
@ -26,14 +26,18 @@ class MinifyNamer extends Namer {
|
|||
|
||||
_FieldNamingRegistry fieldRegistry;
|
||||
|
||||
// You can pass an invalid identifier to this and unlike its non-minifying
|
||||
// counterpart it will never return the proposedName as the new fresh name.
|
||||
/// You can pass an invalid identifier to this and unlike its non-minifying
|
||||
/// counterpart it will never return the proposedName as the new fresh name.
|
||||
///
|
||||
/// [sanitizeForNatives] and [sanitizeForAnnotations] are ignored because the
|
||||
/// minified names will always avoid clashing with annotated names or natives.
|
||||
String getFreshName(String proposedName,
|
||||
Set<String> usedNames,
|
||||
Map<String, String> suggestedNames,
|
||||
{bool ensureSafe: true}) {
|
||||
var freshName;
|
||||
var suggestion = suggestedNames[proposedName];
|
||||
{bool sanitizeForNatives: false,
|
||||
bool sanitizeForAnnotations: false}) {
|
||||
String freshName;
|
||||
String suggestion = suggestedNames[proposedName];
|
||||
if (suggestion != null && !usedNames.contains(suggestion)) {
|
||||
freshName = suggestion;
|
||||
} else {
|
||||
|
@ -44,18 +48,20 @@ class MinifyNamer extends Namer {
|
|||
return freshName;
|
||||
}
|
||||
|
||||
String getClosureVariableName(String name, int id) {
|
||||
String getClosureVariableName(String _, int id) {
|
||||
if (id < ALPHABET_CHARACTERS) {
|
||||
return new String.fromCharCodes([_letterNumber(id)]);
|
||||
}
|
||||
return "${getMappedInstanceName('closure')}_$id";
|
||||
// Fall back to a slightly longer name.
|
||||
String basename = _disambiguateMember(null, 'closure');
|
||||
return '${basename}_$id';
|
||||
}
|
||||
|
||||
// From issue 7554. These should not be used on objects (as instance
|
||||
// variables) because they clash with names from the DOM. However, it is
|
||||
// OK to use them as fields, as we only access fields directly if we know
|
||||
// the receiver type.
|
||||
static const _reservedNativeProperties = const <String>[
|
||||
static const List<String> _reservedNativeProperties = const <String>[
|
||||
'Q', 'a', 'b', 'c', 'd', 'e', 'f', 'r', 'x', 'y', 'z',
|
||||
// 2-letter:
|
||||
'ch', 'cx', 'cy', 'db', 'dx', 'dy', 'fr', 'fx', 'fy', 'go', 'id', 'k1',
|
||||
|
@ -80,9 +86,11 @@ class MinifyNamer extends Namer {
|
|||
'Text', 'time', 'type', 'view', 'warn', 'wrap', 'ZERO'];
|
||||
|
||||
void reserveBackendNames() {
|
||||
for (var name in _reservedNativeProperties) {
|
||||
for (String name in _reservedNativeProperties) {
|
||||
if (name.length < 2) {
|
||||
instanceNameMap[name] = name;
|
||||
// Ensure the 1-letter names are disambiguated to the same name.
|
||||
String disambiguatedName = name;
|
||||
reservePublicMemberName(name, disambiguatedName);
|
||||
}
|
||||
usedInstanceNames.add(name);
|
||||
// Getter and setter names are autogenerated by prepending 'g' and 's' to
|
||||
|
@ -166,12 +174,12 @@ class MinifyNamer extends Namer {
|
|||
// in a predictable order determined by the proposed name. This is in order
|
||||
// to make the renamer stable: small changes in the input should nornally
|
||||
// result in relatively small changes in the output.
|
||||
for (var n = 1; n <= 3; n++) {
|
||||
for (int n = 1; n <= 3; n++) {
|
||||
int h = hash;
|
||||
while (h > 10) {
|
||||
var codes = <int>[_letterNumber(h)];
|
||||
List<int> codes = <int>[_letterNumber(h)];
|
||||
int h2 = h ~/ ALPHABET_CHARACTERS;
|
||||
for (var i = 1; i < n; i++) {
|
||||
for (int i = 1; i < n; i++) {
|
||||
codes.add(_alphaNumericNumber(h2));
|
||||
h2 ~/= ALPHANUMERIC_CHARACTERS;
|
||||
}
|
||||
|
@ -213,9 +221,9 @@ class MinifyNamer extends Namer {
|
|||
/// If we can't find a hash based name in the three-letter space, then base
|
||||
/// the name on a letter and a counter.
|
||||
String _badName(int hash, Set<String> usedNames) {
|
||||
var startLetter = new String.fromCharCodes([_letterNumber(hash)]);
|
||||
var name;
|
||||
var i = 0;
|
||||
String startLetter = new String.fromCharCodes([_letterNumber(hash)]);
|
||||
String name;
|
||||
int i = 0;
|
||||
do {
|
||||
name = "$startLetter${i++}";
|
||||
} while (usedNames.contains(name));
|
||||
|
@ -291,8 +299,7 @@ class _FieldNamingRegistry {
|
|||
nameStore.add(MinifyNamer._reservedNativeProperties[count]);
|
||||
} else {
|
||||
nameStore.add(namer.getFreshName("field$count",
|
||||
namer.usedInstanceNames, namer.suggestedInstanceNames,
|
||||
ensureSafe: true));
|
||||
namer.usedInstanceNames, namer.suggestedInstanceNames));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -422,7 +429,7 @@ class _MixinFieldNamingScope extends _FieldNamingScope {
|
|||
: super.inherit(container, superScope, registry);
|
||||
|
||||
String _nextName() {
|
||||
var proposed = super._nextName();
|
||||
String proposed = super._nextName();
|
||||
return proposed + r'$';
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,7 @@ class RuntimeTypes {
|
|||
JavaScriptBackend get backend => compiler.backend;
|
||||
|
||||
String get getFunctionThatReturnsNullName
|
||||
=> backend.namer.getMappedInstanceName('functionThatReturnsNull');
|
||||
=> backend.namer.internalGlobal('functionThatReturnsNull');
|
||||
|
||||
RuntimeTypes(Compiler compiler)
|
||||
: this.compiler = compiler,
|
||||
|
@ -401,7 +401,7 @@ class RuntimeTypes {
|
|||
String getTypeRepresentationForTypeConstant(DartType type) {
|
||||
JavaScriptBackend backend = compiler.backend;
|
||||
Namer namer = backend.namer;
|
||||
if (type.isDynamic) return namer.getRuntimeTypeName(null);
|
||||
if (type.isDynamic) return namer.runtimeTypeName(null);
|
||||
String name = namer.uniqueNameForTypeConstantElement(type.element);
|
||||
if (!type.element.isClass) return name;
|
||||
InterfaceType interface = type;
|
||||
|
@ -541,7 +541,7 @@ class RuntimeTypes {
|
|||
getTypeEncoding(type, alwaysGenerateFunction: true);
|
||||
if (contextClass != null) {
|
||||
JavaScriptBackend backend = compiler.backend;
|
||||
String contextName = backend.namer.getNameOfClass(contextClass);
|
||||
String contextName = backend.namer.className(contextClass);
|
||||
return js('function () { return #(#, #, #); }',
|
||||
[ backend.emitter.staticFunctionAccess(backend.getComputeSignature()),
|
||||
encoding, this_, js.string(contextName) ]);
|
||||
|
|
|
@ -62,7 +62,7 @@ class ClassStubGenerator {
|
|||
jsAst.Expression receiver =
|
||||
js(isInterceptorClass ? receiverArgumentName : 'this');
|
||||
if (member.isGetter) {
|
||||
String getterName = namer.getterName(member);
|
||||
String getterName = namer.getterForElement(member);
|
||||
if (isInterceptedMethod) {
|
||||
return js('this.#(#)', [getterName, receiver]);
|
||||
}
|
||||
|
|
|
@ -291,8 +291,7 @@ class InterceptorStubGenerator {
|
|||
Selector selector = backend.oneShotInterceptors[name];
|
||||
Set<ClassElement> classes =
|
||||
backend.getInterceptedClassesOn(selector.name);
|
||||
String getInterceptorName =
|
||||
namer.getInterceptorName(backend.getInterceptorMethod, classes);
|
||||
String getInterceptorName = namer.nameForGetInterceptor(classes);
|
||||
|
||||
List<String> parameterNames = <String>[];
|
||||
parameterNames.add('receiver');
|
||||
|
|
|
@ -66,7 +66,7 @@ class Emitter implements emitterTask.Emitter {
|
|||
}
|
||||
|
||||
js.PropertyAccess _globalPropertyAccess(Element element) {
|
||||
String name = namer.getNameX(element);
|
||||
String name = namer.globalPropertyName(element);
|
||||
js.PropertyAccess pa = new js.PropertyAccess.field(
|
||||
new js.VariableUse(namer.globalObjectFor(element)),
|
||||
name);
|
||||
|
@ -76,7 +76,7 @@ class Emitter implements emitterTask.Emitter {
|
|||
@override
|
||||
js.Expression isolateLazyInitializerAccess(FieldElement element) {
|
||||
return js.js('#.#', [namer.globalObjectFor(element),
|
||||
namer.getLazyInitializerName(element)]);
|
||||
namer.lazyInitializerName(element)]);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -103,7 +103,7 @@ class ModelEmitter {
|
|||
|
||||
js.Expression generateStaticClosureAccess(FunctionElement element) {
|
||||
return js.js('#.#()',
|
||||
[namer.globalObjectFor(element), namer.getStaticClosureName(element)]);
|
||||
[namer.globalObjectFor(element), namer.staticClosureName(element)]);
|
||||
}
|
||||
|
||||
js.Expression generateConstantReference(ConstantValue value) {
|
||||
|
@ -320,7 +320,7 @@ class ModelEmitter {
|
|||
compiler.stringClass, compiler.boolClass, compiler.nullClass,
|
||||
compiler.listClass];
|
||||
nativeClassesNeedingUnmangledName.forEach((element) {
|
||||
names.add(new js.Property(js.string(namer.getNameOfClass(element)),
|
||||
names.add(new js.Property(js.string(namer.className(element)),
|
||||
js.string(element.name)));
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
ClassElement superclass = classElement.superclass;
|
||||
String superName = "";
|
||||
if (superclass != null) {
|
||||
superName = namer.getNameOfClass(superclass);
|
||||
superName = namer.className(superclass);
|
||||
}
|
||||
|
||||
if (cls.isMixinApplication) {
|
||||
|
@ -44,6 +44,14 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
emitRuntimeTypeInformation(cls, builder);
|
||||
emitNativeInfo(cls, builder);
|
||||
|
||||
if (classElement == backend.closureClass) {
|
||||
// We add a special getter here to allow for tearing off a closure from
|
||||
// itself.
|
||||
jsAst.Fun function = js('function() { return this; }');
|
||||
String name = namer.getterForPublicMember(Compiler.CALL_OPERATOR_NAME);
|
||||
builder.addProperty(name, function);
|
||||
}
|
||||
|
||||
emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder);
|
||||
}
|
||||
/**
|
||||
|
@ -63,7 +71,7 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
jsAst.Expression constructorAst =
|
||||
_stubGenerator.generateClassConstructor(classElement, fieldNames);
|
||||
|
||||
String constructorName = namer.getNameOfClass(classElement);
|
||||
String constructorName = namer.className(classElement);
|
||||
OutputUnit outputUnit =
|
||||
compiler.deferredLoadTask.outputUnitForElement(classElement);
|
||||
emitter.emitPrecompiledConstructor(
|
||||
|
@ -134,14 +142,14 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
|
||||
if (field.needsInterceptedGetter) {
|
||||
emitter.interceptorEmitter.interceptorInvocationNames.add(
|
||||
namer.getterName(fieldElement));
|
||||
namer.getterForElement(fieldElement));
|
||||
}
|
||||
// TODO(16168): The setter creator only looks at the getter-name.
|
||||
// Even though the setter could avoid the interceptor convention we
|
||||
// currently still need to add the additional argument.
|
||||
if (field.needsInterceptedGetter || field.needsInterceptedSetter) {
|
||||
emitter.interceptorEmitter.interceptorInvocationNames.add(
|
||||
namer.setterName(fieldElement));
|
||||
namer.setterForElement(fieldElement));
|
||||
}
|
||||
|
||||
int code = field.getterFlags + (field.setterFlags << 2);
|
||||
|
@ -483,7 +491,7 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
ClassBuilder builder) {
|
||||
jsAst.Expression code = backend.generatedCode[member];
|
||||
assert(code != null);
|
||||
String setterName = namer.setterNameFromAccessorName(accessorName);
|
||||
String setterName = namer.deriveSetterName(accessorName);
|
||||
compiler.dumpInfoTask.registerElementAst(member,
|
||||
builder.addProperty(setterName, code));
|
||||
generateReflectionDataForFieldGetterOrSetter(
|
||||
|
@ -495,9 +503,9 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
jsAst.Expression function =
|
||||
_stubGenerator.generateGetter(member, fieldName);
|
||||
|
||||
String getterName = namer.getterNameFromAccessorName(accessorName);
|
||||
String getterName = namer.deriveGetterName(accessorName);
|
||||
ClassElement cls = member.enclosingClass;
|
||||
String className = namer.getNameOfClass(cls);
|
||||
String className = namer.className(cls);
|
||||
OutputUnit outputUnit =
|
||||
compiler.deferredLoadTask.outputUnitForElement(member);
|
||||
emitter.cspPrecompiledFunctionFor(outputUnit).add(
|
||||
|
@ -514,9 +522,9 @@ class ClassEmitter extends CodeEmitterHelper {
|
|||
jsAst.Expression function =
|
||||
_stubGenerator.generateSetter(member, fieldName);
|
||||
|
||||
String setterName = namer.setterNameFromAccessorName(accessorName);
|
||||
String setterName = namer.deriveSetterName(accessorName);
|
||||
ClassElement cls = member.enclosingClass;
|
||||
String className = namer.getNameOfClass(cls);
|
||||
String className = namer.className(cls);
|
||||
OutputUnit outputUnit =
|
||||
compiler.deferredLoadTask.outputUnitForElement(member);
|
||||
emitter.cspPrecompiledFunctionFor(outputUnit).add(
|
||||
|
|
|
@ -194,8 +194,7 @@ class OldEmitter implements Emitter {
|
|||
=> '${namer.isolateName}.${lazyInitializerProperty}';
|
||||
String get initName => 'init';
|
||||
|
||||
String get makeConstListProperty
|
||||
=> namer.getMappedInstanceName('makeConstantList');
|
||||
String get makeConstListProperty => namer.internalGlobal('makeConstantList');
|
||||
|
||||
/// The name of the property that contains all field names.
|
||||
///
|
||||
|
@ -205,8 +204,9 @@ class OldEmitter implements Emitter {
|
|||
/// For deferred loading we communicate the initializers via this global var.
|
||||
final String deferredInitializers = r"$dart_deferred_initializers";
|
||||
|
||||
/// All the global state can be passed around with this variable.
|
||||
String get globalsHolder => namer.getMappedGlobalName("globalsHolder");
|
||||
/// Contains the global state that is needed to initialize and load a
|
||||
/// deferred library.
|
||||
String get globalsHolder => namer.internalGlobal("globalsHolder");
|
||||
|
||||
@override
|
||||
jsAst.Expression generateEmbeddedGlobalAccess(String global) {
|
||||
|
@ -219,7 +219,7 @@ class OldEmitter implements Emitter {
|
|||
}
|
||||
|
||||
jsAst.PropertyAccess globalPropertyAccess(Element element) {
|
||||
String name = namer.getNameX(element);
|
||||
String name = namer.globalPropertyName(element);
|
||||
jsAst.PropertyAccess pa = new jsAst.PropertyAccess.field(
|
||||
new jsAst.VariableUse(namer.globalObjectFor(element)),
|
||||
name);
|
||||
|
@ -229,13 +229,13 @@ class OldEmitter implements Emitter {
|
|||
@override
|
||||
jsAst.Expression isolateLazyInitializerAccess(FieldElement element) {
|
||||
return jsAst.js('#.#', [namer.globalObjectFor(element),
|
||||
namer.getLazyInitializerName(element)]);
|
||||
namer.lazyInitializerName(element)]);
|
||||
}
|
||||
|
||||
@override
|
||||
jsAst.Expression isolateStaticClosureAccess(FunctionElement element) {
|
||||
return jsAst.js('#.#()',
|
||||
[namer.globalObjectFor(element), namer.getStaticClosureName(element)]);
|
||||
[namer.globalObjectFor(element), namer.staticClosureName(element)]);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -772,7 +772,7 @@ class OldEmitter implements Emitter {
|
|||
void emitInitialization(Element element, jsAst.Expression initialValue) {
|
||||
jsAst.Expression init =
|
||||
js('$isolateProperties.# = #',
|
||||
[namer.getNameOfGlobalField(element), initialValue]);
|
||||
[namer.globalPropertyName(element), initialValue]);
|
||||
output.addBuffer(jsAst.prettyPrint(init, compiler,
|
||||
monitor: compiler.dumpInfoTask));
|
||||
output.add('$N');
|
||||
|
@ -841,8 +841,8 @@ class OldEmitter implements Emitter {
|
|||
[js(lazyInitializerName),
|
||||
js(isolateProperties),
|
||||
js.string(element.name),
|
||||
js.string(namer.getNameX(element)),
|
||||
js.string(namer.getLazyInitializerName(element)),
|
||||
js.string(namer.globalPropertyName(element)),
|
||||
js.string(namer.lazyInitializerName(element)),
|
||||
code]);
|
||||
}
|
||||
|
||||
|
@ -1223,9 +1223,9 @@ class OldEmitter implements Emitter {
|
|||
// typedefs are only emitted with reflection, which requires lots of
|
||||
// classes.
|
||||
assert(compiler.objectClass != null);
|
||||
builder.superName = namer.getNameOfClass(compiler.objectClass);
|
||||
builder.superName = namer.className(compiler.objectClass);
|
||||
jsAst.Node declaration = builder.toObjectInitializer();
|
||||
String mangledName = namer.getNameX(typedef);
|
||||
String mangledName = namer.globalPropertyName(typedef);
|
||||
String reflectionName = getReflectionName(typedef, mangledName);
|
||||
getElementDescriptor(library)
|
||||
..addProperty(mangledName, declaration)
|
||||
|
|
|
@ -260,7 +260,7 @@ class NsmEmitter extends CodeEmitterHelper {
|
|||
}
|
||||
shortNames.splice.apply(shortNames, calculatedShortNames);
|
||||
}
|
||||
}''', {'objectClass': js.string(namer.getNameOfClass(objectClass)),
|
||||
}''', {'objectClass': js.string(namer.className(objectClass)),
|
||||
'diffEncoding': js.string('$diffEncoding')}));
|
||||
} else {
|
||||
// No useDiffEncoding version.
|
||||
|
@ -269,7 +269,7 @@ class NsmEmitter extends CodeEmitterHelper {
|
|||
statements.add(js.statement(
|
||||
'var objectClassObject = processedClasses.collected[#objectClass],'
|
||||
' shortNames = #diffEncoding.split(",")',
|
||||
{'objectClass': js.string(namer.getNameOfClass(objectClass)),
|
||||
{'objectClass': js.string(namer.className(objectClass)),
|
||||
'diffEncoding': js.string('$diffEncoding')}));
|
||||
if (!minify) {
|
||||
statements.add(js.statement('var longNames = #longs.split(",")',
|
||||
|
|
|
@ -59,7 +59,7 @@ class ParameterStubGenerator {
|
|||
// If the method is intercepted, we need to also pass the actual receiver.
|
||||
int extraArgumentCount = isInterceptedMethod ? 1 : 0;
|
||||
// Use '$receiver' to avoid clashes with other parameter names. Using
|
||||
// '$receiver' works because [:namer.safeName:] used for getting parameter
|
||||
// '$receiver' works because namer.safeVariableName used for getting parameter
|
||||
// names never returns a name beginning with a single '$'.
|
||||
String receiverArgumentName = r'$receiver';
|
||||
|
||||
|
@ -84,7 +84,7 @@ class ParameterStubGenerator {
|
|||
|
||||
int parameterIndex = 0;
|
||||
parameters.orderedForEachParameter((ParameterElement element) {
|
||||
String jsName = backend.namer.safeName(element.name);
|
||||
String jsName = backend.namer.safeVariableName(element.name);
|
||||
assert(jsName != receiverArgumentName);
|
||||
if (count < optionalParameterStart) {
|
||||
parametersBuffer[count] = new jsAst.Parameter(jsName);
|
||||
|
@ -126,7 +126,7 @@ class ParameterStubGenerator {
|
|||
} else if (member.isInstanceMember) {
|
||||
if (needsSuperGetter(member)) {
|
||||
ClassElement superClass = member.enclosingClass;
|
||||
String methodName = namer.getNameOfInstanceMember(member);
|
||||
String methodName = namer.instanceMethodName(member);
|
||||
// When redirecting, we must ensure that we don't end up in a subclass.
|
||||
// We thus can't just invoke `this.foo$1.call(filledInArguments)`.
|
||||
// Instead we need to call the statically resolved target.
|
||||
|
@ -140,7 +140,7 @@ class ParameterStubGenerator {
|
|||
} else {
|
||||
body = js.statement(
|
||||
'return this.#(#);',
|
||||
[namer.getNameOfInstanceMember(member), argumentsBuffer]);
|
||||
[namer.instanceMethodName(member), argumentsBuffer]);
|
||||
}
|
||||
} else {
|
||||
body = js.statement('return #(#)',
|
||||
|
|
|
@ -216,7 +216,7 @@ class ProgramBuilder {
|
|||
// a static field.
|
||||
_registry.registerHolder(namer.globalObjectForConstant(initialValue));
|
||||
js.Expression code = _task.emitter.constantReference(initialValue);
|
||||
String name = namer.getNameOfGlobalField(element);
|
||||
String name = namer.globalPropertyName(element);
|
||||
bool isFinal = false;
|
||||
bool isLazy = false;
|
||||
|
||||
|
@ -252,7 +252,7 @@ class ProgramBuilder {
|
|||
// before code generation.
|
||||
if (code == null) return null;
|
||||
|
||||
String name = namer.getNameOfGlobalField(element);
|
||||
String name = namer.globalPropertyName(element);
|
||||
bool isFinal = element.isFinal;
|
||||
bool isLazy = true;
|
||||
// TODO(floitsch): we shouldn't update the registry in the middle of
|
||||
|
@ -308,7 +308,7 @@ class ProgramBuilder {
|
|||
assert(_compiler.hasIncrementalSupport);
|
||||
|
||||
List<Field> instanceFields = _buildFields(element, false);
|
||||
String name = namer.getNameOfClass(element);
|
||||
String name = namer.className(element);
|
||||
|
||||
return new Class(
|
||||
element, name, null, [], instanceFields, [], [], [], [], [], null,
|
||||
|
@ -369,8 +369,7 @@ class ProgramBuilder {
|
|||
if (element == backend.closureClass) {
|
||||
// We add a special getter here to allow for tearing off a closure from
|
||||
// itself.
|
||||
String name = namer.getterNameFromAccessorName(
|
||||
namer.getMappedInstanceName(Compiler.CALL_OPERATOR_NAME));
|
||||
String name = namer.getterForPublicMember(Compiler.CALL_OPERATOR_NAME);
|
||||
js.Fun function = js.js('function() { return this; }');
|
||||
callStubs.add(_buildStubMethod(name, function));
|
||||
}
|
||||
|
@ -398,7 +397,7 @@ class ProgramBuilder {
|
|||
isChecks.add(_buildStubMethod(name, code));
|
||||
});
|
||||
|
||||
String name = namer.getNameOfClass(element);
|
||||
String name = namer.className(element);
|
||||
String holderName = namer.globalObjectFor(element);
|
||||
// TODO(floitsch): we shouldn't update the registry in the middle of
|
||||
// building a class.
|
||||
|
@ -485,7 +484,7 @@ class ProgramBuilder {
|
|||
}
|
||||
|
||||
DartMethod _buildMethod(FunctionElement element) {
|
||||
String name = namer.getNameOfInstanceMember(element);
|
||||
String name = namer.methodPropertyName(element);
|
||||
js.Expression code = backend.generatedCode[element];
|
||||
|
||||
// TODO(kasperl): Figure out under which conditions code is null.
|
||||
|
@ -501,7 +500,7 @@ class ProgramBuilder {
|
|||
bool canBeApplied = _methodCanBeApplied(element);
|
||||
|
||||
String aliasName = backend.isAliasedSuperMember(element)
|
||||
? namer.getNameOfAliasedSuperMember(element)
|
||||
? namer.aliasedSuperMemberPropertyName(element)
|
||||
: null;
|
||||
|
||||
if (isNotApplyTarget) {
|
||||
|
@ -516,7 +515,7 @@ class ProgramBuilder {
|
|||
(canBeReflected && !element.isOperator);
|
||||
assert(canTearOff ||
|
||||
!universe.methodsNeedingSuperGetter.contains(element));
|
||||
tearOffName = namer.getterName(element);
|
||||
tearOffName = namer.getterForElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -692,7 +691,7 @@ class ProgramBuilder {
|
|||
}
|
||||
|
||||
StaticDartMethod _buildStaticMethod(FunctionElement element) {
|
||||
String name = namer.getNameOfMember(element);
|
||||
String name = namer.methodPropertyName(element);
|
||||
String holder = namer.globalObjectFor(element);
|
||||
js.Expression code = backend.generatedCode[element];
|
||||
|
||||
|
@ -705,7 +704,7 @@ class ProgramBuilder {
|
|||
universe.staticFunctionsNeedingGetter.contains(element));
|
||||
|
||||
String tearOffName =
|
||||
needsTearOff ? namer.getStaticClosureName(element) : null;
|
||||
needsTearOff ? namer.staticClosureName(element) : null;
|
||||
|
||||
|
||||
String callName = null;
|
||||
|
|
|
@ -284,7 +284,7 @@ class RuntimeTypeGenerator {
|
|||
|
||||
StubMethod _generateTypeVariableReader(ClassElement cls,
|
||||
TypeVariableElement element) {
|
||||
String name = namer.readTypeVariableName(element);
|
||||
String name = namer.nameForReadTypeVariable(element);
|
||||
int index = RuntimeTypes.getTypeVariableIndex(element);
|
||||
jsAst.Expression computeTypeVariable;
|
||||
|
||||
|
|
|
@ -3943,15 +3943,15 @@ class SsaBuilder extends ResolvedVisitor {
|
|||
stack.add(addConstantString(backend.namer.operatorIsPrefix));
|
||||
} else if (name == 'JS_OBJECT_CLASS_NAME') {
|
||||
// TODO(floitsch): this should be a JS_NAME.
|
||||
String name = backend.namer.getRuntimeTypeName(compiler.objectClass);
|
||||
String name = backend.namer.runtimeTypeName(compiler.objectClass);
|
||||
stack.add(addConstantString(name));
|
||||
} else if (name == 'JS_NULL_CLASS_NAME') {
|
||||
// TODO(floitsch): this should be a JS_NAME.
|
||||
String name = backend.namer.getRuntimeTypeName(compiler.nullClass);
|
||||
String name = backend.namer.runtimeTypeName(compiler.nullClass);
|
||||
stack.add(addConstantString(name));
|
||||
} else if (name == 'JS_FUNCTION_CLASS_NAME') {
|
||||
// TODO(floitsch): this should be a JS_NAME.
|
||||
String name = backend.namer.getRuntimeTypeName(compiler.functionClass);
|
||||
String name = backend.namer.runtimeTypeName(compiler.functionClass);
|
||||
stack.add(addConstantString(name));
|
||||
} else if (name == 'JS_OPERATOR_AS_PREFIX') {
|
||||
// TODO(floitsch): this should be a JS_NAME.
|
||||
|
@ -4148,7 +4148,7 @@ class SsaBuilder extends ResolvedVisitor {
|
|||
// TODO(ahe): Creating a string here is unfortunate. It is slow (due to
|
||||
// string concatenation in the implementation), and may prevent
|
||||
// segmentation of '$'.
|
||||
String substitutionNameString = backend.namer.getNameForRti(cls);
|
||||
String substitutionNameString = backend.namer.runtimeTypeName(cls);
|
||||
HInstruction substitutionName = graph.addConstantString(
|
||||
new ast.LiteralDartString(substitutionNameString), compiler);
|
||||
pushInvokeStatic(null,
|
||||
|
|
|
@ -1473,8 +1473,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
|
|||
|
||||
void visitInterceptor(HInterceptor node) {
|
||||
registry.registerSpecializedGetInterceptor(node.interceptedClasses);
|
||||
String name = backend.namer.getInterceptorName(
|
||||
backend.getInterceptorMethod, node.interceptedClasses);
|
||||
String name = backend.namer.nameForGetInterceptor(node.interceptedClasses);
|
||||
var isolate = new js.VariableUse(
|
||||
backend.namer.globalObjectFor(backend.interceptorsLibrary));
|
||||
use(node.receiver);
|
||||
|
@ -1520,7 +1519,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
|
|||
void visitInvokeConstructorBody(HInvokeConstructorBody node) {
|
||||
use(node.inputs[0]);
|
||||
js.Expression object = pop();
|
||||
String methodName = backend.namer.getNameOfInstanceMember(node.element);
|
||||
String methodName = backend.namer.instanceMethodName(node.element);
|
||||
List<js.Expression> arguments = visitArguments(node.inputs);
|
||||
push(js.propertyCall(object, methodName, arguments), node);
|
||||
registry.registerStaticUse(node.element);
|
||||
|
@ -1660,7 +1659,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
|
|||
methodName = backend.namer.invocationName(selector);
|
||||
} else {
|
||||
assert(invariant(node, compiler.hasIncrementalSupport));
|
||||
methodName = backend.namer.getNameOfInstanceMember(superMethod);
|
||||
methodName = backend.namer.instanceMethodName(superMethod);
|
||||
}
|
||||
push(js.js('#.#.call(#)',
|
||||
[backend.emitter.prototypeAccess(superClass,
|
||||
|
@ -1671,7 +1670,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
|
|||
use(node.receiver);
|
||||
push(
|
||||
js.js('#.#(#)', [
|
||||
pop(), backend.namer.getNameOfAliasedSuperMember(superMethod),
|
||||
pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod),
|
||||
visitArguments(node.inputs, start: 1)]), // Skip receiver argument.
|
||||
node);
|
||||
}
|
||||
|
@ -2632,7 +2631,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
|
|||
} else {
|
||||
backend.emitter.registerReadTypeVariable(element);
|
||||
push(js.js('#.#()',
|
||||
[pop(), backend.namer.readTypeVariableName(element)]));
|
||||
[pop(), backend.namer.nameForReadTypeVariable(element)]));
|
||||
}
|
||||
} else {
|
||||
push(js.js('#(#)', [
|
||||
|
|
|
@ -289,7 +289,8 @@ class HInstructionStringifier implements HVisitor<String> {
|
|||
String value = temporaryId(node.inputs[0]);
|
||||
if (node.interceptedClasses != null) {
|
||||
JavaScriptBackend backend = compiler.backend;
|
||||
String cls = backend.namer.getInterceptorSuffix(node.interceptedClasses);
|
||||
String cls =
|
||||
backend.namer.suffixForGetInterceptor(node.interceptedClasses);
|
||||
return "Intercept ($cls): $value";
|
||||
}
|
||||
return "Intercept: $value";
|
||||
|
|
|
@ -85,8 +85,7 @@ void main() {
|
|||
compiler.listClass
|
||||
];
|
||||
JavaScriptBackend backend = compiler.backend;
|
||||
Iterable<String> nativeNames =
|
||||
nativeClasses.map(backend.namer.getNameOfClass);
|
||||
Iterable<String> nativeNames = nativeClasses.map(backend.namer.className);
|
||||
expectedNames.addAll(nativeNames);
|
||||
|
||||
Set recordedNames = new Set()
|
||||
|
|
47
tests/html/custom_element_method_clash_test.dart
Normal file
47
tests/html/custom_element_method_clash_test.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library custom_elements_method_clash;
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:html';
|
||||
import 'package:unittest/html_individual_config.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
class CustomElement extends HtmlElement {
|
||||
factory CustomElement() => new Element.tag('x-custom');
|
||||
|
||||
CustomElement.created() : super.created() {
|
||||
}
|
||||
|
||||
// Try to clash with native 'appendChild' method.
|
||||
void appendChild() {
|
||||
throw 'Gotcha!';
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
useHtmlIndividualConfiguration();
|
||||
|
||||
setUp(() => customElementsReady);
|
||||
|
||||
group('test', () {
|
||||
test('test', () {
|
||||
document.registerElement('x-custom', CustomElement);
|
||||
CustomElement custom = new CustomElement();
|
||||
document.body.children.add(custom);
|
||||
|
||||
// Will call appendChild in JS.
|
||||
custom.children.add(new DivElement()..text = 'Hello world!');
|
||||
|
||||
try {
|
||||
custom.appendChild(); // Make sure method is not tree shaken.
|
||||
fail('appendChild did not throw');
|
||||
} catch(e) {
|
||||
expect(e, equals('Gotcha!'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
22
tests/html/custom_element_method_clash_test.html
Normal file
22
tests/html/custom_element_method_clash_test.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="dart.unittest" content="full-stack-traces">
|
||||
<title> custom_element_method_clash_test </title>
|
||||
<style>
|
||||
.unittest-table { font-family:monospace; border:1px; }
|
||||
.unittest-pass { background: #6b3;}
|
||||
.unittest-fail { background: #d55;}
|
||||
.unittest-error { background: #a11;}
|
||||
</style>
|
||||
<script src="/packages/web_components/webcomponents.js"></script>
|
||||
<script src="/packages/web_components/dart_support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1> Running custom_element_method_clash_test </h1>
|
||||
<script type="text/javascript"
|
||||
src="/root_dart/tools/testing/dart/test_controller.js"></script>
|
||||
%TEST_SCRIPTS%
|
||||
</body>
|
||||
</html>
|
39
tests/html/custom_element_name_clash_test.dart
Normal file
39
tests/html/custom_element_name_clash_test.dart
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library custom_elements_name_clash;
|
||||
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:html';
|
||||
import 'package:unittest/html_individual_config.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
|
||||
class CustomElement extends HtmlElement {
|
||||
factory CustomElement() => new Element.tag('x-custom');
|
||||
|
||||
CustomElement.created() : super.created() {
|
||||
}
|
||||
|
||||
// Try to clash with native 'appendChild' method.
|
||||
var appendChild = 123;
|
||||
}
|
||||
|
||||
main() {
|
||||
useHtmlIndividualConfiguration();
|
||||
|
||||
setUp(() => customElementsReady);
|
||||
|
||||
group('test', () {
|
||||
test('test', () {
|
||||
document.registerElement('x-custom', CustomElement);
|
||||
CustomElement custom = new CustomElement();
|
||||
document.body.children.add(custom);
|
||||
// Will call appendChild in JS.
|
||||
custom.children.add(new DivElement()..text = 'Hello world!');
|
||||
});
|
||||
});
|
||||
}
|
22
tests/html/custom_element_name_clash_test.html
Normal file
22
tests/html/custom_element_name_clash_test.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="dart.unittest" content="full-stack-traces">
|
||||
<title> custom_element_name_clash_test </title>
|
||||
<style>
|
||||
.unittest-table { font-family:monospace; border:1px; }
|
||||
.unittest-pass { background: #6b3;}
|
||||
.unittest-fail { background: #d55;}
|
||||
.unittest-error { background: #a11;}
|
||||
</style>
|
||||
<script src="/packages/web_components/webcomponents.js"></script>
|
||||
<script src="/packages/web_components/dart_support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1> Running custom_element_name_clash_test </h1>
|
||||
<script type="text/javascript"
|
||||
src="/root_dart/tools/testing/dart/test_controller.js"></script>
|
||||
%TEST_SCRIPTS%
|
||||
</body>
|
||||
</html>
|
14
tests/language/constructor_name_clash_lib.dart
Normal file
14
tests/language/constructor_name_clash_lib.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library lib;
|
||||
|
||||
var global = 0;
|
||||
|
||||
class A {
|
||||
A() {
|
||||
global += 10;
|
||||
try {} catch(e) {} // no inline
|
||||
}
|
||||
}
|
18
tests/language/constructor_name_clash_test.dart
Normal file
18
tests/language/constructor_name_clash_test.dart
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'constructor_name_clash_lib.dart' as lib;
|
||||
|
||||
class A extends lib.A {
|
||||
A() {
|
||||
lib.global += 100;
|
||||
try {} catch(e) {} // no inline
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new A();
|
||||
Expect.equals(110, lib.global);
|
||||
}
|
47
tests/language/is_operator_clash_test.dart
Normal file
47
tests/language/is_operator_clash_test.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
class A {
|
||||
}
|
||||
|
||||
class $B extends A {
|
||||
}
|
||||
|
||||
class C implements $B {
|
||||
// Try to clash with dart2js's isCLASS field.
|
||||
var isB = false;
|
||||
var $isB = false;
|
||||
var is$B = false;
|
||||
var is$$B = false;
|
||||
var $is$B = false;
|
||||
|
||||
var isA = false;
|
||||
var $isA = false;
|
||||
var is$A = false;
|
||||
var is$$A = false;
|
||||
var $is$A = false;
|
||||
}
|
||||
|
||||
int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
|
||||
|
||||
main() {
|
||||
var things = [new A(), new $B(), new C()];
|
||||
|
||||
var a = things[inscrutable(0)];
|
||||
Expect.isTrue(a is A);
|
||||
Expect.isFalse(a is $B);
|
||||
Expect.isFalse(a is C);
|
||||
|
||||
var b = things[inscrutable(1)];
|
||||
Expect.isTrue(b is A);
|
||||
Expect.isTrue(b is $B);
|
||||
Expect.isFalse(b is C);
|
||||
|
||||
var c = things[inscrutable(2)];
|
||||
Expect.isTrue(c is A);
|
||||
Expect.isTrue(c is $B);
|
||||
Expect.isTrue(c is C);
|
||||
}
|
36
tests/language/named_parameter_clash_test.dart
Normal file
36
tests/language/named_parameter_clash_test.dart
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class Foo {
|
||||
m({a, b, c}) {
|
||||
try {} catch(e) {} // no inline
|
||||
return 'Foo $a $b $c';
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
m(z, {a$b, c}) {
|
||||
try {} catch(e) {} // no inline
|
||||
var ab = a$b;
|
||||
return 'Bar $z $ab $c';
|
||||
}
|
||||
}
|
||||
|
||||
inscrutable(xs, i) => i == 0 ? xs[0] : inscrutable(xs.sublist(1), i-1);
|
||||
|
||||
main() {
|
||||
var list = [new Foo(), new Bar()];
|
||||
var foo = inscrutable(list, 0);
|
||||
var bar = inscrutable(list, 1);
|
||||
|
||||
Expect.equals(r'Foo a b c', foo.m(a: 'a', b: 'b', c: 'c'));
|
||||
Expect.equals(r'Bar z a$b c', bar.m('z', a$b: r'a$b', c: 'c'));
|
||||
|
||||
Expect.throws(() => foo.m('z', a$b: r'a$b', c: 'c'),
|
||||
(e) => e is NoSuchMethodError);
|
||||
Expect.throws(() => bar.m(a: 'a', b: 'b', c: 'c'),
|
||||
(e) => e is NoSuchMethodError);
|
||||
}
|
14
tests/language/private_clash_lib.dart
Normal file
14
tests/language/private_clash_lib.dart
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library a$_b;
|
||||
|
||||
class B {
|
||||
var _c$ = 10; // With library prefix: _a$_b$_c$
|
||||
|
||||
getValueA() {
|
||||
try {} catch(e) {} // no inline
|
||||
return this._c$;
|
||||
}
|
||||
}
|
22
tests/language/private_clash_test.dart
Normal file
22
tests/language/private_clash_test.dart
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library a;
|
||||
|
||||
import 'private_clash_lib.dart' as lib;
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class A extends lib.B {
|
||||
var _b$_c$ = 100; // With library prefix: _a$_b$_c$
|
||||
|
||||
getValueB() {
|
||||
try {} catch(e) {} // no inline
|
||||
return this._b$_c$;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
A a = new A();
|
||||
Expect.equals(110, a.getValueA() + a.getValueB());
|
||||
}
|
Loading…
Reference in a new issue