OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
7 | 7 |
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
(...skipping 849 matching lines...) Loading... |
860 | 860 |
861 if (m.element is PropertyAccessorElement) { | 861 if (m.element is PropertyAccessorElement) { |
862 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); | 862 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); |
863 } | 863 } |
864 | 864 |
865 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 865 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { |
866 hasIterator = true; | 866 hasIterator = true; |
867 jsMethods.add(_emitIterable(type)); | 867 jsMethods.add(_emitIterable(type)); |
868 } | 868 } |
869 } else if (m is FieldDeclaration) { | 869 } else if (m is FieldDeclaration) { |
870 if (_extensionTypes.contains(element)) { | 870 if (_extensionTypes.isNativeClass(element)) { |
871 jsMethods.addAll(_emitNativeFieldAccessors(m)); | 871 jsMethods.addAll(_emitNativeFieldAccessors(m)); |
872 continue; | 872 continue; |
873 } | 873 } |
874 if (m.isStatic) continue; | 874 if (m.isStatic) continue; |
875 for (VariableDeclaration field in m.fields.variables) { | 875 for (VariableDeclaration field in m.fields.variables) { |
876 if (virtualFields.containsKey(field.element)) { | 876 if (virtualFields.containsKey(field.element)) { |
877 jsMethods.addAll(_emitVirtualFieldAccessor(field, virtualFields)); | 877 jsMethods.addAll(_emitVirtualFieldAccessor(field, virtualFields)); |
878 } | 878 } |
879 } | 879 } |
880 } | 880 } |
(...skipping 49 matching lines...) Loading... |
930 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, | 930 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, |
931 InterfaceType type, List<ClassElement> superclasses) { | 931 InterfaceType type, List<ClassElement> superclasses) { |
932 var methodElement = method.element as PropertyAccessorElement; | 932 var methodElement = method.element as PropertyAccessorElement; |
933 var field = methodElement.variable; | 933 var field = methodElement.variable; |
934 if (!field.isSynthetic) return null; | 934 if (!field.isSynthetic) return null; |
935 var propertyOverrideResult = checkForPropertyOverride( | 935 var propertyOverrideResult = checkForPropertyOverride( |
936 methodElement.variable, superclasses, _extensionTypes); | 936 methodElement.variable, superclasses, _extensionTypes); |
937 | 937 |
938 // Generate a corresponding virtual getter / setter. | 938 // Generate a corresponding virtual getter / setter. |
939 var name = _elementMemberName(methodElement, | 939 var name = _elementMemberName(methodElement, |
940 allowExtensions: _extensionTypes.contains(type.element)); | 940 allowExtensions: _extensionTypes.isNativeClass(type.element)); |
941 if (method.isGetter) { | 941 if (method.isGetter) { |
942 // Generate a setter | 942 // Generate a setter |
943 if (field.setter != null || !propertyOverrideResult.foundSetter) | 943 if (field.setter != null || !propertyOverrideResult.foundSetter) |
944 return null; | 944 return null; |
945 var fn = js.call('function(value) { super[#] = value; }', [name]); | 945 var fn = js.call('function(value) { super[#] = value; }', [name]); |
946 return new JS.Method(name, fn, isSetter: true); | 946 return new JS.Method(name, fn, isSetter: true); |
947 } else { | 947 } else { |
948 // Generate a getter | 948 // Generate a getter |
949 if (field.getter != null || !propertyOverrideResult.foundGetter) | 949 if (field.getter != null || !propertyOverrideResult.foundGetter) |
950 return null; | 950 return null; |
(...skipping 42 matching lines...) Loading... |
993 | 993 |
994 /// Gets the JS peer for this Dart type if any, otherwise null. | 994 /// Gets the JS peer for this Dart type if any, otherwise null. |
995 /// | 995 /// |
996 /// For example for dart:_interceptors `JSArray` this will return "Array", | 996 /// For example for dart:_interceptors `JSArray` this will return "Array", |
997 /// referring to the JavaScript built-in `Array` type. | 997 /// referring to the JavaScript built-in `Array` type. |
998 String _getJSPeerName(ClassElement classElem) { | 998 String _getJSPeerName(ClassElement classElem) { |
999 var jsPeerName = getAnnotationName( | 999 var jsPeerName = getAnnotationName( |
1000 classElem, | 1000 classElem, |
1001 (a) => | 1001 (a) => |
1002 isJsPeerInterface(a) || | 1002 isJsPeerInterface(a) || |
1003 isNativeAnnotation(a) && _extensionTypes.contains(classElem)); | 1003 isNativeAnnotation(a) && _extensionTypes.isNativeClass(classElem)); |
1004 if (jsPeerName != null && jsPeerName.contains(',')) { | 1004 if (jsPeerName != null && jsPeerName.contains(',')) { |
1005 jsPeerName = jsPeerName.split(',')[0]; | 1005 jsPeerName = jsPeerName.split(',')[0]; |
1006 } | 1006 } |
1007 return jsPeerName; | 1007 return jsPeerName; |
1008 } | 1008 } |
1009 | 1009 |
1010 void _registerExtensionType(ClassElement classElem, List<JS.Statement> body) { | 1010 void _registerExtensionType(ClassElement classElem, List<JS.Statement> body) { |
1011 var jsPeerName = _getJSPeerName(classElem); | 1011 var jsPeerName = _getJSPeerName(classElem); |
1012 if (jsPeerName != null) { | 1012 if (jsPeerName != null) { |
1013 // TODO(jmesserly): this copies the dynamic members. | 1013 // TODO(jmesserly): this copies the dynamic members. |
(...skipping 70 matching lines...) Loading... |
1084 | 1084 |
1085 /// If a concrete class implements one of our extensions, we might need to | 1085 /// If a concrete class implements one of our extensions, we might need to |
1086 /// add forwarders. | 1086 /// add forwarders. |
1087 void _defineExtensionMembers(List<ExecutableElement> extensions, | 1087 void _defineExtensionMembers(List<ExecutableElement> extensions, |
1088 JS.Expression className, List<JS.Statement> body) { | 1088 JS.Expression className, List<JS.Statement> body) { |
1089 // If a concrete class implements one of our extensions, we might need to | 1089 // If a concrete class implements one of our extensions, we might need to |
1090 // add forwarders. | 1090 // add forwarders. |
1091 if (extensions.isNotEmpty) { | 1091 if (extensions.isNotEmpty) { |
1092 var methodNames = <JS.Expression>[]; | 1092 var methodNames = <JS.Expression>[]; |
1093 for (var e in extensions) { | 1093 for (var e in extensions) { |
1094 methodNames.add(_elementMemberName(e)); | 1094 methodNames.add(_elementMemberName(e, allowExtensions: false)); |
1095 } | 1095 } |
1096 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ | 1096 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ |
1097 className, | 1097 className, |
1098 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) | 1098 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) |
1099 ])); | 1099 ])); |
1100 } | 1100 } |
1101 } | 1101 } |
1102 | 1102 |
1103 /// Emit the signature on the class recording the runtime type information | 1103 /// Emit the signature on the class recording the runtime type information |
1104 void _emitClassSignature( | 1104 void _emitClassSignature( |
(...skipping 16 matching lines...) Loading... |
1121 var sNames = <JS.Expression>[]; | 1121 var sNames = <JS.Expression>[]; |
1122 for (MethodDeclaration node in methods) { | 1122 for (MethodDeclaration node in methods) { |
1123 if (!(node.isSetter || node.isGetter || node.isAbstract)) { | 1123 if (!(node.isSetter || node.isGetter || node.isAbstract)) { |
1124 var name = node.name.name; | 1124 var name = node.name.name; |
1125 var element = node.element; | 1125 var element = node.element; |
1126 var inheritedElement = | 1126 var inheritedElement = |
1127 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); | 1127 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); |
1128 if (inheritedElement != null && inheritedElement.type == element.type) { | 1128 if (inheritedElement != null && inheritedElement.type == element.type) { |
1129 continue; | 1129 continue; |
1130 } | 1130 } |
1131 var memberName = _elementMemberName(element); | 1131 var memberName = _elementMemberName(element, |
| 1132 allowExtensions: _extensionTypes.isNativeClass(classElem)); |
1132 var parts = _emitFunctionTypeParts(element.type); | 1133 var parts = _emitFunctionTypeParts(element.type); |
1133 var property = | 1134 var property = |
1134 new JS.Property(memberName, new JS.ArrayInitializer(parts)); | 1135 new JS.Property(memberName, new JS.ArrayInitializer(parts)); |
1135 if (node.isStatic) { | 1136 if (node.isStatic) { |
1136 tStatics.add(property); | 1137 tStatics.add(property); |
1137 sNames.add(memberName); | 1138 sNames.add(memberName); |
1138 } else { | 1139 } else { |
1139 tMethods.add(property); | 1140 tMethods.add(property); |
1140 } | 1141 } |
1141 } | 1142 } |
(...skipping 31 matching lines...) Loading... |
1173 body.add(js.statement('dart.setSignature(#, #);', [className, sig])); | 1174 body.add(js.statement('dart.setSignature(#, #);', [className, sig])); |
1174 } | 1175 } |
1175 } | 1176 } |
1176 | 1177 |
1177 /// Ensure `dartx.` symbols we will use are present. | 1178 /// Ensure `dartx.` symbols we will use are present. |
1178 void _initExtensionSymbols( | 1179 void _initExtensionSymbols( |
1179 ClassElement classElem, | 1180 ClassElement classElem, |
1180 List<MethodDeclaration> methods, | 1181 List<MethodDeclaration> methods, |
1181 List<FieldDeclaration> fields, | 1182 List<FieldDeclaration> fields, |
1182 List<JS.Statement> body) { | 1183 List<JS.Statement> body) { |
1183 if (_extensionTypes.contains(classElem)) { | 1184 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
1184 var dartxNames = <JS.Expression>[]; | 1185 var dartxNames = <JS.Expression>[]; |
1185 for (var m in methods) { | 1186 for (var m in methods) { |
1186 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1187 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
1187 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); | 1188 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); |
1188 } | 1189 } |
1189 } | 1190 } |
1190 for (var f in fields) { | 1191 for (var f in fields) { |
1191 if (!f.isStatic) { | 1192 if (!f.isStatic) { |
1192 for (var d in f.fields.variables) { | 1193 for (var d in f.fields.variables) { |
1193 if (d.element.isPublic) { | 1194 if (d.element.isPublic) { |
1194 dartxNames.add( | 1195 dartxNames.add( |
1195 _elementMemberName(d.element.getter, allowExtensions: false)); | 1196 _elementMemberName(d.element.getter, allowExtensions: false)); |
1196 } | 1197 } |
1197 } | 1198 } |
1198 } | 1199 } |
1199 } | 1200 } |
1200 if (dartxNames.isNotEmpty) { | 1201 if (dartxNames.isNotEmpty) { |
1201 body.add(js.statement('dart.defineExtensionNames(#)', | 1202 body.add(js.statement('dart.defineExtensionNames(#)', |
1202 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1203 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
1203 } | 1204 } |
1204 } | 1205 } |
1205 } | 1206 } |
1206 | 1207 |
1207 List<ExecutableElement> _extensionsToImplement(ClassElement element) { | 1208 List<ExecutableElement> _extensionsToImplement(ClassElement element) { |
1208 var members = <ExecutableElement>[]; | 1209 var members = <ExecutableElement>[]; |
1209 if (_extensionTypes.contains(element)) return members; | 1210 if (_extensionTypes.isNativeClass(element)) return members; |
1210 | 1211 |
1211 // Collect all extension types we implement. | 1212 // Collect all extension types we implement. |
1212 var type = element.type; | 1213 var type = element.type; |
1213 var types = new Set<ClassElement>(); | 1214 var types = _extensionTypes.collectNativeInterfaces(element); |
1214 _collectExtensions(type, types); | |
1215 if (types.isEmpty) return members; | 1215 if (types.isEmpty) return members; |
1216 | 1216 |
1217 // Collect all possible extension method names. | 1217 // Collect all possible extension method names. |
1218 var extensionMembers = new HashSet<String>(); | 1218 var extensionMembers = new HashSet<String>(); |
1219 for (var t in types) { | 1219 for (var t in types) { |
1220 for (var m in [t.methods, t.accessors].expand((e) => e)) { | 1220 for (var m in [t.methods, t.accessors].expand((e) => e)) { |
1221 if (!m.isStatic) extensionMembers.add(m.name); | 1221 if (!m.isStatic) extensionMembers.add(m.name); |
1222 } | 1222 } |
1223 } | 1223 } |
1224 | 1224 |
1225 // Collect all of extension methods this type implements. | 1225 // Collect all of extension methods this type implements. |
1226 for (var m in [type.methods, type.accessors].expand((e) => e)) { | 1226 for (var m in [type.methods, type.accessors].expand((e) => e)) { |
1227 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { | 1227 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { |
1228 members.add(m); | 1228 members.add(m); |
1229 } | 1229 } |
1230 } | 1230 } |
1231 return members; | 1231 return members; |
1232 } | 1232 } |
1233 | 1233 |
1234 /// Collections the type and all supertypes, including interfaces, but | |
1235 /// excluding [Object]. | |
1236 void _collectExtensions(InterfaceType type, Set<ClassElement> types) { | |
1237 if (type.isObject) return; | |
1238 var element = type.element; | |
1239 if (_extensionTypes.contains(element)) types.add(element); | |
1240 for (var m in type.mixins.reversed) { | |
1241 _collectExtensions(m, types); | |
1242 } | |
1243 for (var i in type.interfaces) { | |
1244 _collectExtensions(i, types); | |
1245 } | |
1246 _collectExtensions(type.superclass, types); | |
1247 } | |
1248 | |
1249 /// Generates the implicit default constructor for class C of the form | 1234 /// Generates the implicit default constructor for class C of the form |
1250 /// `C() : super() {}`. | 1235 /// `C() : super() {}`. |
1251 JS.Method _emitImplicitConstructor( | 1236 JS.Method _emitImplicitConstructor( |
1252 ClassDeclaration node, | 1237 ClassDeclaration node, |
1253 List<FieldDeclaration> fields, | 1238 List<FieldDeclaration> fields, |
1254 Map<FieldElement, JS.TemporaryId> virtualFields) { | 1239 Map<FieldElement, JS.TemporaryId> virtualFields) { |
1255 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); | 1240 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); |
1256 | 1241 |
1257 // If we don't have a method body, skip this. | 1242 // If we don't have a method body, skip this. |
1258 var superCall = _superConstructorCall(node.element); | 1243 var superCall = _superConstructorCall(node.element); |
(...skipping 399 matching lines...) Loading... |
1658 fn.params.isNotEmpty) { | 1643 fn.params.isNotEmpty) { |
1659 // []= methods need to return the value. We could also address this at | 1644 // []= methods need to return the value. We could also address this at |
1660 // call sites, but it's cleaner to instead transform the operator method
. | 1645 // call sites, but it's cleaner to instead transform the operator method
. |
1661 fn = _alwaysReturnLastParameter(fn); | 1646 fn = _alwaysReturnLastParameter(fn); |
1662 } | 1647 } |
1663 | 1648 |
1664 fn = _makeGenericFunction(fn); | 1649 fn = _makeGenericFunction(fn); |
1665 } | 1650 } |
1666 | 1651 |
1667 return annotate( | 1652 return annotate( |
1668 new JS.Method(_elementMemberName(node.element), fn, | 1653 new JS.Method( |
| 1654 _elementMemberName(node.element, |
| 1655 allowExtensions: _extensionTypes.isNativeClass(type.element)), |
| 1656 fn, |
1669 isGetter: node.isGetter, | 1657 isGetter: node.isGetter, |
1670 isSetter: node.isSetter, | 1658 isSetter: node.isSetter, |
1671 isStatic: node.isStatic), | 1659 isStatic: node.isStatic), |
1672 node, | 1660 node, |
1673 node.element); | 1661 node.element); |
1674 } | 1662 } |
1675 | 1663 |
1676 /// Transform the function so the last parameter is always returned. | 1664 /// Transform the function so the last parameter is always returned. |
1677 /// | 1665 /// |
1678 /// This is useful for indexed set methods, which otherwise would not have | 1666 /// This is useful for indexed set methods, which otherwise would not have |
(...skipping 1855 matching lines...) Loading... |
3534 // Is this a member on `Object`? | 3522 // Is this a member on `Object`? |
3535 if (!isObjectProperty(memberName)) { | 3523 if (!isObjectProperty(memberName)) { |
3536 return false; | 3524 return false; |
3537 } | 3525 } |
3538 | 3526 |
3539 // Check if the target could be `null`, is dynamic, or may be an extension | 3527 // Check if the target could be `null`, is dynamic, or may be an extension |
3540 // native type. In all of those cases we need defensive code generation. | 3528 // native type. In all of those cases we need defensive code generation. |
3541 var type = getStaticType(target); | 3529 var type = getStaticType(target); |
3542 return isNullable(target) || | 3530 return isNullable(target) || |
3543 type.isDynamic || | 3531 type.isDynamic || |
3544 (_extensionTypes.contains(type.element) && target is! SuperExpression); | 3532 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); |
3545 } | 3533 } |
3546 | 3534 |
3547 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 3535 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
3548 JS.Expression _emitAccess( | 3536 JS.Expression _emitAccess( |
3549 Expression target, SimpleIdentifier memberId, DartType resultType) { | 3537 Expression target, SimpleIdentifier memberId, DartType resultType) { |
3550 Element member = memberId.staticElement; | 3538 Element member = memberId.staticElement; |
3551 if (member is PropertyAccessorElement) { | 3539 if (member is PropertyAccessorElement) { |
3552 member = (member as PropertyAccessorElement).variable; | 3540 member = (member as PropertyAccessorElement).variable; |
3553 } | 3541 } |
3554 bool isStatic = member is ClassMemberElement && member.isStatic; | 3542 bool isStatic = member is ClassMemberElement && member.isStatic; |
(...skipping 582 matching lines...) Loading... |
4137 name = '+$name'; | 4125 name = '+$name'; |
4138 } | 4126 } |
4139 | 4127 |
4140 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 4128 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
4141 var baseType = type; | 4129 var baseType = type; |
4142 while (baseType is TypeParameterType) { | 4130 while (baseType is TypeParameterType) { |
4143 baseType = baseType.element.bound; | 4131 baseType = baseType.element.bound; |
4144 } | 4132 } |
4145 if (allowExtensions && | 4133 if (allowExtensions && |
4146 baseType != null && | 4134 baseType != null && |
4147 _extensionTypes.contains(baseType.element) && | 4135 _extensionTypes.hasNativeSubtype(baseType) && |
4148 !isObjectProperty(name)) { | 4136 !isObjectProperty(name)) { |
4149 return js.call('dartx.#', _propertyName(name)); | 4137 return js.call('dartx.#', _propertyName(name)); |
4150 } | 4138 } |
4151 | 4139 |
4152 return _propertyName(name); | 4140 return _propertyName(name); |
4153 } | 4141 } |
4154 | 4142 |
4155 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { | 4143 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { |
4156 return _privateNames | 4144 return _privateNames |
4157 .putIfAbsent(library, () => new HashMap()) | 4145 .putIfAbsent(library, () => new HashMap()) |
(...skipping 141 matching lines...) Loading... |
4299 } | 4287 } |
4300 | 4288 |
4301 bool isLibraryPrefix(Expression node) => | 4289 bool isLibraryPrefix(Expression node) => |
4302 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4290 node is SimpleIdentifier && node.staticElement is PrefixElement; |
4303 | 4291 |
4304 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4292 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
4305 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4293 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
4306 | 4294 |
4307 bool _isDartRuntime(LibraryElement l) => | 4295 bool _isDartRuntime(LibraryElement l) => |
4308 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4296 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |