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 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 1146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1157 var nameProperties = new List<JS.Property>(fields.length); | 1157 var nameProperties = new List<JS.Property>(fields.length); |
1158 for (var i = 0; i < fields.length; ++i) { | 1158 for (var i = 0; i < fields.length; ++i) { |
1159 nameProperties[i] = new JS.Property( | 1159 nameProperties[i] = new JS.Property( |
1160 js.number(i), js.string('${type.name}.${fields[i].name}')); | 1160 js.number(i), js.string('${type.name}.${fields[i].name}')); |
1161 } | 1161 } |
1162 var nameMap = new JS.ObjectInitializer(nameProperties, multiline: true); | 1162 var nameMap = new JS.ObjectInitializer(nameProperties, multiline: true); |
1163 var toStringF = new JS.Method(js.string('toString'), | 1163 var toStringF = new JS.Method(js.string('toString'), |
1164 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); | 1164 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); |
1165 | 1165 |
1166 // Create enum class | 1166 // Create enum class |
1167 JS.Property build(String name, List<JS.Property> elements) { | |
1168 var o = | |
1169 new JS.ObjectInitializer(elements, multiline: elements.length > 1); | |
1170 // TODO(vsm): Remove | |
Jennifer Messerly
2017/01/24 03:51:03
was this code copied from somewhere else?
Jacob
2017/01/24 19:12:32
That is scary. I had moved that to a shared helper
| |
1171 var e = js.call('() => #', o); | |
1172 return new JS.Property(_propertyName(name), e); | |
1173 } | |
1174 | |
1167 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), | 1175 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), |
1168 _emitClassHeritage(element), [constructor, toStringF]); | 1176 _emitClassHeritage(element), [constructor, toStringF]); |
1169 var id = _emitTopLevelName(element); | 1177 var id = _emitTopLevelName(element); |
1178 | |
1179 // Emit metadata for synthetic enum index member. | |
1180 // TODO(jacobr): make field readonly when that is supported. | |
1181 var tInstanceFields = <JS.Property>[new JS.Property(_emitMemberName('index') , _emitAnnotatedType(intClass.type, null))]; | |
Jennifer Messerly
2017/01/24 03:51:03
format?
Jacob
2017/01/24 19:12:32
fixed.
| |
1182 var sigFields = <JS.Property>[build('fields', tInstanceFields)]; | |
1183 var sig = new JS.ObjectInitializer(sigFields); | |
1184 | |
1170 var result = [ | 1185 var result = [ |
1171 js.statement('# = #', [id, classExpr]) | 1186 js.statement('# = #', [id, classExpr]), |
1187 _callHelperStatement('setSignature(#, #);', [id, sig]) | |
1172 ]; | 1188 ]; |
1173 | 1189 |
1174 // defineEnumValues internally depends on dart.constList which uses | 1190 // defineEnumValues internally depends on dart.constList which uses |
1175 // _interceptors.JSArray. | 1191 // _interceptors.JSArray. |
1176 _declareBeforeUse(_jsArray); | 1192 _declareBeforeUse(_jsArray); |
1177 | 1193 |
1178 // Create static fields for each enum value, and the "values" getter | 1194 // Create static fields for each enum value, and the "values" getter |
1179 result.add(_callHelperStatement('defineEnumValues(#, #);', [ | 1195 result.add(_callHelperStatement('defineEnumValues(#, #);', [ |
1180 id, | 1196 id, |
1181 new JS.ArrayInitializer(fields.map((f) => _propertyName(f.name)).toList(), | 1197 new JS.ArrayInitializer(fields.map((f) => _propertyName(f.name)).toList(), |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1499 } else if (property.isSetter) { | 1515 } else if (property.isSetter) { |
1500 addProperty('isSetter', js.boolean(true)); | 1516 addProperty('isSetter', js.boolean(true)); |
1501 | 1517 |
1502 fnArgs.add(args); | 1518 fnArgs.add(args); |
1503 positionalArgs = new JS.ArrayInitializer([args]); | 1519 positionalArgs = new JS.ArrayInitializer([args]); |
1504 } | 1520 } |
1505 } | 1521 } |
1506 | 1522 |
1507 var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [ | 1523 var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [ |
1508 _runtimeModule, | 1524 _runtimeModule, |
1509 _declareMemberName(method), | 1525 _declareMemberName(method, useDisplayName: true), |
1510 positionalArgs, | 1526 positionalArgs, |
1511 new JS.ObjectInitializer(invocationProps) | 1527 new JS.ObjectInitializer(invocationProps) |
1512 ]); | 1528 ]); |
1513 | 1529 |
1514 if (!method.returnType.isDynamic) { | 1530 if (!method.returnType.isDynamic) { |
1515 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); | 1531 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); |
1516 } | 1532 } |
1517 | 1533 |
1518 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), | 1534 var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]), |
1519 typeParams: _emitTypeFormals(method.type.typeFormals)); | 1535 typeParams: _emitTypeFormals(method.type.typeFormals)); |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1942 } | 1958 } |
1943 } | 1959 } |
1944 if (dartxNames.isNotEmpty) { | 1960 if (dartxNames.isNotEmpty) { |
1945 body.add(_callHelperStatement('defineExtensionNames(#)', | 1961 body.add(_callHelperStatement('defineExtensionNames(#)', |
1946 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1962 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
1947 } | 1963 } |
1948 } | 1964 } |
1949 } | 1965 } |
1950 | 1966 |
1951 List<ExecutableElement> _extensionsToImplement(ClassElement element) { | 1967 List<ExecutableElement> _extensionsToImplement(ClassElement element) { |
1952 var members = <ExecutableElement>[]; | 1968 if (_extensionTypes.isNativeClass(element)) return []; |
1953 if (_extensionTypes.isNativeClass(element)) return members; | |
1954 | 1969 |
1955 // Collect all extension types we implement. | 1970 // Collect all extension types we implement. |
1956 var type = element.type; | 1971 var type = element.type; |
1957 var types = _extensionTypes.collectNativeInterfaces(element); | 1972 var types = _extensionTypes.collectNativeInterfaces(element); |
1958 if (types.isEmpty) return members; | 1973 if (types.isEmpty) return []; |
1959 | 1974 |
1975 var members = new Set<ExecutableElement>(); | |
1960 // Collect all possible extension method names. | 1976 // Collect all possible extension method names. |
1961 var extensionMembers = new HashSet<String>(); | 1977 var extensionMembers = new HashSet<String>(); |
1962 for (var t in types) { | 1978 for (var t in types) { |
1963 for (var m in [t.methods, t.accessors].expand((e) => e)) { | 1979 for (var m in [t.methods, t.accessors].expand((e) => e)) { |
1964 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name); | 1980 if (!m.isStatic && m.isPublic) extensionMembers.add(m.name); |
1965 } | 1981 } |
1966 } | 1982 } |
1967 | 1983 |
1968 // Collect all of extension methods this type implements. | 1984 // Collect all of extension methods this type implements. |
1969 for (var m in [type.methods, type.accessors].expand((e) => e)) { | 1985 for (var m in [type.methods, type.accessors].expand((e) => e)) { |
1970 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { | 1986 if (!m.isStatic && !m.isAbstract && extensionMembers.contains(m.name)) { |
1971 members.add(m); | 1987 members.add(m); |
1972 } | 1988 } |
1973 } | 1989 } |
1974 return members; | 1990 members.addAll(_collectMockMethods(type) |
1991 .where((m) => extensionMembers.contains(m.name))); | |
1992 return members.toList(); | |
1975 } | 1993 } |
1976 | 1994 |
1977 /// Generates the implicit default constructor for class C of the form | 1995 /// Generates the implicit default constructor for class C of the form |
1978 /// `C() : super() {}`. | 1996 /// `C() : super() {}`. |
1979 JS.Method _emitImplicitConstructor( | 1997 JS.Method _emitImplicitConstructor( |
1980 ClassDeclaration node, | 1998 ClassDeclaration node, |
1981 List<FieldDeclaration> fields, | 1999 List<FieldDeclaration> fields, |
1982 Map<FieldElement, JS.TemporaryId> virtualFields) { | 2000 Map<FieldElement, JS.TemporaryId> virtualFields) { |
1983 // If we don't have a method body, skip this. | 2001 // If we don't have a method body, skip this. |
1984 var superCall = _superConstructorCall(node.element); | 2002 var superCall = _superConstructorCall(node.element); |
(...skipping 3488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5473 } | 5491 } |
5474 JS.Expression result = _visit(node); | 5492 JS.Expression result = _visit(node); |
5475 if (isNullable(node)) result = _callHelper('test(#)', result); | 5493 if (isNullable(node)) result = _callHelper('test(#)', result); |
5476 return result; | 5494 return result; |
5477 } | 5495 } |
5478 | 5496 |
5479 /// Like [_emitMemberName], but for declaration sites. | 5497 /// Like [_emitMemberName], but for declaration sites. |
5480 /// | 5498 /// |
5481 /// Unlike call sites, we always have an element available, so we can use it | 5499 /// Unlike call sites, we always have an element available, so we can use it |
5482 /// directly rather than computing the relevant options for [_emitMemberName]. | 5500 /// directly rather than computing the relevant options for [_emitMemberName]. |
5483 JS.Expression _declareMemberName(ExecutableElement e, {bool useExtension}) { | 5501 JS.Expression _declareMemberName(ExecutableElement e, |
5484 String name; | 5502 {bool useExtension, useDisplayName = false}) { |
5485 if (e is PropertyAccessorElement) { | 5503 var name = (e is PropertyAccessorElement) ? e.variable.name : e.name; |
5486 name = e.variable.name; | |
5487 } else { | |
5488 name = e.name; | |
5489 } | |
5490 return _emitMemberName(name, | 5504 return _emitMemberName(name, |
5491 isStatic: e.isStatic, | 5505 isStatic: e.isStatic, |
5492 useExtension: | 5506 useExtension: |
5493 useExtension ?? _extensionTypes.isNativeClass(e.enclosingElement)); | 5507 useExtension ?? _extensionTypes.isNativeClass(e.enclosingElement), |
5508 useDisplayName: useDisplayName); | |
5494 } | 5509 } |
5495 | 5510 |
5496 /// This handles member renaming for private names and operators. | 5511 /// This handles member renaming for private names and operators. |
5497 /// | 5512 /// |
5498 /// Private names are generated using ES6 symbols: | 5513 /// Private names are generated using ES6 symbols: |
5499 /// | 5514 /// |
5500 /// // At the top of the module: | 5515 /// // At the top of the module: |
5501 /// let _x = Symbol('_x'); | 5516 /// let _x = Symbol('_x'); |
5502 /// let _y = Symbol('_y'); | 5517 /// let _y = Symbol('_y'); |
5503 /// ... | 5518 /// ... |
(...skipping 26 matching lines...) Expand all Loading... | |
5530 /// | 5545 /// |
5531 /// Unary minus looks like: `x._negate()`. | 5546 /// Unary minus looks like: `x._negate()`. |
5532 /// | 5547 /// |
5533 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 5548 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
5534 /// helper, that checks for null. The user defined method is called '=='. | 5549 /// helper, that checks for null. The user defined method is called '=='. |
5535 /// | 5550 /// |
5536 JS.Expression _emitMemberName(String name, | 5551 JS.Expression _emitMemberName(String name, |
5537 {DartType type, | 5552 {DartType type, |
5538 bool isStatic: false, | 5553 bool isStatic: false, |
5539 bool useExtension, | 5554 bool useExtension, |
5555 bool useDisplayName: false, | |
5540 Element element}) { | 5556 Element element}) { |
5541 // Static members skip the rename steps and may require JS interop renames. | 5557 // Static members skip the rename steps and may require JS interop renames. |
5542 if (isStatic) { | 5558 if (isStatic) { |
5543 return _emitJSInteropStaticMemberName(element) ?? _propertyName(name); | 5559 return _emitJSInteropStaticMemberName(element) ?? _propertyName(name); |
5544 } | 5560 } |
5545 | 5561 |
5546 if (name.startsWith('_')) { | 5562 if (name.startsWith('_')) { |
5547 return _emitPrivateNameSymbol(currentLibrary, name); | 5563 return _emitPrivateNameSymbol(currentLibrary, name); |
5548 } | 5564 } |
5549 | 5565 |
5550 // When generating synthetic names, we use _ as the prefix, since Dart names | 5566 // When generating synthetic names, we use _ as the prefix, since Dart names |
5551 // won't have this (eliminated above), nor will static names reach here. | 5567 // won't have this (eliminated above), nor will static names reach here. |
5552 switch (name) { | 5568 if (!useDisplayName) { |
5553 case '[]': | 5569 switch (name) { |
5554 name = '_get'; | 5570 case '[]': |
5555 break; | 5571 name = '_get'; |
5556 case '[]=': | 5572 break; |
5557 name = '_set'; | 5573 case '[]=': |
5558 break; | 5574 name = '_set'; |
5559 case 'unary-': | 5575 break; |
5560 name = '_negate'; | 5576 case 'unary-': |
5561 break; | 5577 name = '_negate'; |
5562 case 'constructor': | 5578 break; |
5563 case 'prototype': | 5579 case 'constructor': |
5564 name = '_$name'; | 5580 case 'prototype': |
5565 break; | 5581 name = '_$name'; |
5582 break; | |
5583 } | |
5566 } | 5584 } |
5567 | 5585 |
5568 var result = _propertyName(name); | 5586 var result = _propertyName(name); |
5569 | 5587 |
5570 if (useExtension == null) { | 5588 if (useExtension == null) { |
5571 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 5589 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
5572 var baseType = type; | 5590 var baseType = type; |
5573 while (baseType is TypeParameterType) { | 5591 while (baseType is TypeParameterType) { |
5574 baseType = (baseType.element as TypeParameterElement).bound; | 5592 baseType = (baseType.element as TypeParameterElement).bound; |
5575 } | 5593 } |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5831 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5849 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5832 var prefix = targetIdentifier.staticElement as PrefixElement; | 5850 var prefix = targetIdentifier.staticElement as PrefixElement; |
5833 | 5851 |
5834 // The library the prefix is referring to must come from a deferred import. | 5852 // The library the prefix is referring to must come from a deferred import. |
5835 var containingLibrary = resolutionMap | 5853 var containingLibrary = resolutionMap |
5836 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5854 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5837 .library; | 5855 .library; |
5838 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5856 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5839 return imports.length == 1 && imports[0].isDeferred; | 5857 return imports.length == 1 && imports[0].isDeferred; |
5840 } | 5858 } |
OLD | NEW |