Index: pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart |
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart |
index ba964c12685e45c4239be1d6cb9d720e79d204ed..9d27c4665f4668975e83966d9b29d6e5f2f6d0cc 100644 |
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart |
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart |
@@ -21,6 +21,7 @@ import '../../deferred_load.dart' show OutputUnit; |
import '../../elements/elements.dart' |
show |
ClassElement, |
+ ConstructorBodyElement, |
Element, |
FieldElement, |
FunctionSignature, |
@@ -29,6 +30,7 @@ import '../../elements/elements.dart' |
TypedefElement; |
import '../../elements/entities.dart'; |
import '../../elements/entity_utils.dart' as utils; |
+import '../../elements/names.dart'; |
import '../../hash/sha1.dart' show Hasher; |
import '../../io/code_output.dart'; |
import '../../io/location_provider.dart' show LocationCollector; |
@@ -405,8 +407,7 @@ class Emitter extends js_emitter.EmitterBase { |
} |
/// In minified mode we want to keep the name for the most common core types. |
- bool _isNativeTypeNeedingReflectionName(Element element) { |
- if (!element.isClass) return false; |
+ bool _isNativeTypeNeedingReflectionName(ClassEntity element) { |
return (element == commonElements.intClass || |
element == commonElements.doubleClass || |
element == commonElements.numClass || |
@@ -416,7 +417,35 @@ class Emitter extends js_emitter.EmitterBase { |
element == commonElements.listClass); |
} |
- /// Returns the "reflection name" of an [Element] or [Selector]. |
+ /// Returns the "reflection name" of a [ClassEntity], if needed. |
+ /// |
+ /// The reflection name of class 'C' is 'C'. |
+ /// An anonymous mixin application has no reflection name. |
+ /// |
+ /// This is used by js_mirrors.dart. |
+ String getReflectionClassName(ClassEntity cls, jsAst.Name mangledName) { |
+ String name = cls.name; |
+ if (backend.mirrorsData.shouldRetainName(name) || |
+ // Make sure to retain names of common native types. |
+ _isNativeTypeNeedingReflectionName(cls)) { |
+ // TODO(ahe): Enable the next line when I can tell the difference between |
+ // an instance method and a global. They may have the same mangled name. |
+ // if (recordedMangledNames.contains(mangledName)) return null; |
+ recordedMangledNames.add(mangledName); |
+ if (cls.isClosure) { |
+ // Closures are synthesized and their name might conflict with existing |
+ // globals. Assign an illegal name, and make sure they don't clash |
+ // with each other. |
+ return " $name"; |
+ } |
+ if (_elementEnvironment.isUnnamedMixinApplication(cls)) return null; |
+ return cls.name; |
+ } |
+ return null; |
+ } |
+ |
+ /// Returns the "reflection name" of a [MemberEntity], if needed. |
+ /// |
/// The reflection name of a getter 'foo' is 'foo'. |
/// The reflection name of a setter 'foo' is 'foo='. |
/// The reflection name of a method 'foo' is 'foo:N:M:O', where N is the |
@@ -424,100 +453,124 @@ class Emitter extends js_emitter.EmitterBase { |
/// O is the named arguments. |
/// The reflection name of a constructor is similar to a regular method but |
/// starts with 'new '. |
- /// The reflection name of class 'C' is 'C'. |
- /// An anonymous mixin application has no reflection name. |
+ /// |
/// This is used by js_mirrors.dart. |
- String getReflectionName(elementOrSelector, jsAst.Name mangledName) { |
- String name = elementOrSelector.name; |
+ String getReflectionMemberName(MemberEntity member, jsAst.Name mangledName) { |
+ String name = member.name; |
if (backend.mirrorsData.shouldRetainName(name) || |
- elementOrSelector is Element && |
- // Make sure to retain names of unnamed constructors, and |
- // for common native types. |
- ((name == '' && |
- backend.mirrorsData |
- .isAccessibleByReflection(elementOrSelector)) || |
- _isNativeTypeNeedingReflectionName(elementOrSelector))) { |
+ // Make sure to retain names of unnamed constructors. |
+ (name == '' && |
+ backend.mirrorsData.isMemberAccessibleByReflection(member))) { |
// TODO(ahe): Enable the next line when I can tell the difference between |
// an instance method and a global. They may have the same mangled name. |
// if (recordedMangledNames.contains(mangledName)) return null; |
recordedMangledNames.add(mangledName); |
- return getReflectionNameInternal(elementOrSelector, mangledName); |
+ return getReflectionMemberNameInternal(member, mangledName); |
} |
return null; |
} |
- String getReflectionNameInternal(elementOrSelector, jsAst.Name mangledName) { |
- String name = namer.privateName(elementOrSelector.memberName); |
- if (elementOrSelector.isGetter) return name; |
- if (elementOrSelector.isSetter) { |
- if (mangledName is! SetterName) return '$name='; |
- SetterName setterName = mangledName; |
- jsAst.Name base = setterName.base; |
- jsAst.Name getter = namer.deriveGetterName(base); |
- mangledFieldNames.putIfAbsent(getter, () => name); |
- assert(mangledFieldNames[getter] == name); |
- recordedMangledNames.add(getter); |
- // TODO(karlklose,ahe): we do not actually need to store information |
- // about the name of this setter in the output, but it is needed for |
- // marking the function as invokable by reflection. |
- return '$name='; |
+ String getReflectionMemberNameInternal( |
+ MemberEntity member, jsAst.Name mangledName) { |
+ if (member is ConstructorBodyElement) { |
+ return null; |
} |
- if (elementOrSelector is Element && elementOrSelector.isClosure) { |
- // Closures are synthesized and their name might conflict with existing |
- // globals. Assign an illegal name, and make sure they don't clash |
- // with each other. |
- return " $name"; |
+ if (member.isGetter) { |
+ return _getReflectionGetterName(member.memberName); |
+ } else if (member.isSetter) { |
+ return _getReflectionSetterName(member.memberName, mangledName); |
+ } else if (member.isConstructor) { |
+ ConstructorEntity constructor = member; |
+ String name = utils.reconstructConstructorName(constructor); |
+ return _getReflectionCallStructureName( |
+ name, constructor.parameterStructure.callStructure); |
+ } else if (member.isFunction) { |
+ FunctionEntity function = member; |
+ return _getReflectionFunctionName( |
+ member.memberName, function.parameterStructure.callStructure); |
} |
- if (elementOrSelector is Selector || |
- elementOrSelector.isFunction || |
- elementOrSelector.isConstructor) { |
- int positionalParameterCount; |
- String namedArguments = ''; |
- bool isConstructor = false; |
- if (elementOrSelector is Selector) { |
- CallStructure callStructure = elementOrSelector.callStructure; |
- positionalParameterCount = callStructure.positionalArgumentCount; |
- namedArguments = namedParametersAsReflectionNames(callStructure); |
+ throw reporter.internalError( |
+ member, 'Do not know how to reflect on this $member.'); |
+ } |
+ |
+ /// Returns the "reflection name" of a [Selector], if needed. |
+ /// |
+ /// The reflection name of a getter 'foo' is 'foo'. |
+ /// The reflection name of a setter 'foo' is 'foo='. |
+ /// The reflection name of a method 'foo' is 'foo:N:M:O', where N is the |
+ /// number of required arguments, M is the number of optional arguments, and |
+ /// O is the named arguments. |
+ /// |
+ /// This is used by js_mirrors.dart. |
+ String getReflectionSelectorName(Selector selector, jsAst.Name mangledName) { |
+ String name = selector.name; |
+ if (backend.mirrorsData.shouldRetainName(name)) { |
+ // TODO(ahe): Enable the next line when I can tell the difference between |
+ // an instance method and a global. They may have the same mangled name. |
+ // if (recordedMangledNames.contains(mangledName)) return null; |
+ recordedMangledNames.add(mangledName); |
+ if (selector.isGetter) { |
+ return _getReflectionGetterName(selector.memberName); |
+ } else if (selector.isSetter) { |
+ return _getReflectionSetterName(selector.memberName, mangledName); |
} else { |
- MethodElement function = elementOrSelector; |
- if (function.isConstructor) { |
- isConstructor = true; |
- name = utils.reconstructConstructorName(function); |
- } |
- FunctionSignature signature = function.functionSignature; |
- positionalParameterCount = signature.requiredParameterCount; |
- if (signature.optionalParametersAreNamed) { |
- var names = []; |
- for (Element e in signature.optionalParameters) { |
- names.add(e.name); |
- } |
- CallStructure callStructure = |
- new CallStructure(positionalParameterCount, names); |
- namedArguments = namedParametersAsReflectionNames(callStructure); |
- } else { |
- // Named parameters are handled differently by mirrors. For unnamed |
- // parameters, they are actually required if invoked |
- // reflectively. Also, if you have a method c(x) and c([x]) they both |
- // get the same mangled name, so they must have the same reflection |
- // name. |
- positionalParameterCount += signature.optionalParameterCount; |
- } |
+ return _getReflectionFunctionName( |
+ selector.memberName, selector.callStructure); |
} |
- String suffix = '$name:$positionalParameterCount$namedArguments'; |
- return (isConstructor) ? 'new $suffix' : suffix; |
} |
- Element element = elementOrSelector; |
- if (element.isGenerativeConstructorBody) { |
- return null; |
- } else if (element.isClass) { |
- ClassElement cls = element; |
- if (cls.isUnnamedMixinApplication) return null; |
- return cls.name; |
- } else if (element.isTypedef) { |
- return element.name; |
+ return null; |
+ } |
+ |
+ /// Returns the "reflection name" of a [TypedefElement], if needed. |
+ /// |
+ /// The reflection name of typedef 'F' is 'F'. |
+ /// |
+ /// This is used by js_mirrors.dart. |
+ String getReflectionTypedefName( |
+ TypedefElement typedef, jsAst.Name mangledName) { |
+ String name = typedef.name; |
+ if (backend.mirrorsData.shouldRetainName(name)) { |
+ // TODO(ahe): Enable the next line when I can tell the difference between |
+ // an instance method and a global. They may have the same mangled name. |
+ // if (recordedMangledNames.contains(mangledName)) return null; |
+ recordedMangledNames.add(mangledName); |
+ return typedef.name; |
} |
- throw reporter.internalError( |
- element, 'Do not know how to reflect on this $element.'); |
+ return null; |
+ } |
+ |
+ String _getReflectionGetterName(Name memberName) { |
+ return namer.privateName(memberName); |
+ } |
+ |
+ String _getReflectionSetterName(Name memberName, jsAst.Name mangledName) { |
+ String name = namer.privateName(memberName); |
+ if (mangledName is! SetterName) return '$name='; |
+ SetterName setterName = mangledName; |
+ jsAst.Name base = setterName.base; |
+ jsAst.Name getter = namer.deriveGetterName(base); |
+ mangledFieldNames.putIfAbsent(getter, () => name); |
+ assert(mangledFieldNames[getter] == name); |
+ recordedMangledNames.add(getter); |
+ // TODO(karlklose,ahe): we do not actually need to store information |
+ // about the name of this setter in the output, but it is needed for |
+ // marking the function as invokable by reflection. |
+ return '$name='; |
+ } |
+ |
+ String _getReflectionFunctionName( |
+ Name memberName, CallStructure callStructure) { |
+ String name = namer.privateName(memberName); |
+ return _getReflectionCallStructureName(name, callStructure); |
+ } |
+ |
+ String _getReflectionCallStructureName( |
+ String name, CallStructure callStructure, |
+ {bool isConstructor: false}) { |
+ int positionalParameterCount = callStructure.positionalArgumentCount; |
+ String namedArguments = namedParametersAsReflectionNames(callStructure); |
+ String suffix = '$name:$positionalParameterCount$namedArguments'; |
+ return isConstructor ? 'new $suffix' : suffix; |
} |
String namedParametersAsReflectionNames(CallStructure structure) { |
@@ -1133,7 +1186,7 @@ class Emitter extends js_emitter.EmitterBase { |
builder.superName = namer.className(commonElements.objectClass); |
jsAst.Node declaration = builder.toObjectInitializer(); |
jsAst.Name mangledName = namer.globalPropertyNameForType(typedef); |
- String reflectionName = getReflectionName(typedef, mangledName); |
+ String reflectionName = getReflectionTypedefName(typedef, mangledName); |
getLibraryDescriptor(library, mainFragment) |
..addProperty(mangledName, declaration) |
..addPropertyByName("+$reflectionName", js.string('')); |