Chromium Code Reviews| 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 | 6 |
| 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| 10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 Expression _cascadeTarget; | 74 Expression _cascadeTarget; |
| 75 | 75 |
| 76 /// The variable for the current catch clause | 76 /// The variable for the current catch clause |
| 77 SimpleIdentifier _catchParameter; | 77 SimpleIdentifier _catchParameter; |
| 78 | 78 |
| 79 /// In an async* function, this represents the stream controller parameter. | 79 /// In an async* function, this represents the stream controller parameter. |
| 80 JS.TemporaryId _asyncStarController; | 80 JS.TemporaryId _asyncStarController; |
| 81 | 81 |
| 82 final _privateNames = | 82 final _privateNames = |
| 83 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); | 83 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); |
| 84 final _virtualFields = new HashMap<VariableDeclaration, JS.TemporaryId>(); | |
|
Jennifer Messerly
2016/04/25 22:47:04
Generally we don't use AST nodes as hash keys. Sho
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 85 final _virtualFieldSymbols = new HashMap<ClassElement, List<JS.Statement>>(); | |
|
Jennifer Messerly
2016/04/25 22:47:04
do we need this map? could we simply keep a List<J
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 84 final _initializingFormalTemps = | 86 final _initializingFormalTemps = |
| 85 new HashMap<ParameterElement, JS.TemporaryId>(); | 87 new HashMap<ParameterElement, JS.TemporaryId>(); |
| 86 | 88 |
| 87 final _dartxVar = new JS.Identifier('dartx'); | 89 final _dartxVar = new JS.Identifier('dartx'); |
| 88 final _runtimeLibVar = new JS.Identifier('dart'); | 90 final _runtimeLibVar = new JS.Identifier('dart'); |
| 89 final namedArgumentTemp = new JS.TemporaryId('opts'); | 91 final namedArgumentTemp = new JS.TemporaryId('opts'); |
| 90 | 92 |
| 91 final _hasDeferredSupertype = new HashSet<ClassElement>(); | 93 final _hasDeferredSupertype = new HashSet<ClassElement>(); |
| 92 | 94 |
| 93 /// The type provider from the current Analysis [context]. | 95 /// The type provider from the current Analysis [context]. |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 524 for (var member in node.members) { | 526 for (var member in node.members) { |
| 525 if (member is ConstructorDeclaration) { | 527 if (member is ConstructorDeclaration) { |
| 526 ctors.add(member); | 528 ctors.add(member); |
| 527 } else if (member is FieldDeclaration) { | 529 } else if (member is FieldDeclaration) { |
| 528 (member.isStatic ? staticFields : fields).add(member); | 530 (member.isStatic ? staticFields : fields).add(member); |
| 529 } else if (member is MethodDeclaration) { | 531 } else if (member is MethodDeclaration) { |
| 530 methods.add(member); | 532 methods.add(member); |
| 531 } | 533 } |
| 532 } | 534 } |
| 533 | 535 |
| 536 JS.Expression className; | |
| 537 if (classElem.typeParameters.isNotEmpty) { | |
| 538 className = new JS.Identifier(classElem.name); | |
|
Jennifer Messerly
2016/04/25 22:47:04
there was a comment below:
"// Generic classes wil
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 539 } else { | |
| 540 className = _emitTopLevelName(classElem); | |
| 541 } | |
| 542 | |
| 534 var allFields = new List.from(fields)..addAll(staticFields); | 543 var allFields = new List.from(fields)..addAll(staticFields); |
| 535 var classExpr = _emitClassExpression( | 544 var classExpr = _emitClassExpression( |
| 536 classElem, _emitClassMethods(node, ctors, fields), | 545 classElem, _emitClassMethods(node, ctors, fields, className, classElem), |
| 537 fields: allFields); | 546 fields: allFields); |
| 538 | 547 |
| 539 var body = <JS.Statement>[]; | 548 var body = <JS.Statement>[]; |
| 540 var extensions = _extensionsToImplement(classElem); | 549 var extensions = _extensionsToImplement(classElem); |
| 541 _initExtensionSymbols(classElem, methods, fields, body); | 550 _initExtensionSymbols(classElem, methods, fields, body); |
| 542 | 551 |
| 543 // Emit the class, e.g. `core.Object = class Object { ... }` | 552 // Emit the class, e.g. `core.Object = class Object { ... }` |
| 544 JS.Expression className = _defineClass(classElem, classExpr, body); | 553 _defineClass(classElem, className, classExpr, body); |
| 545 | 554 |
| 546 // Emit things that come after the ES6 `class ... { ... }`. | 555 // Emit things that come after the ES6 `class ... { ... }`. |
| 547 _setBaseClass(classElem, className, body); | 556 _setBaseClass(classElem, className, body); |
| 548 _defineNamedConstructors(ctors, body, className); | 557 _defineNamedConstructors(ctors, body, className); |
| 549 _emitVirtualFields(classElem, fields, className, body); | 558 _emitVirtualFieldSymbols(classElem, body); |
| 550 _emitClassSignature(methods, classElem, ctors, extensions, className, body); | 559 _emitClassSignature(methods, classElem, ctors, extensions, className, body); |
| 551 _defineExtensionMembers(extensions, className, body); | 560 _defineExtensionMembers(extensions, className, body); |
| 552 _emitClassMetadata(node.metadata, className, body); | 561 _emitClassMetadata(node.metadata, className, body); |
| 553 | 562 |
| 554 JS.Statement classDef = _statement(body); | 563 JS.Statement classDef = _statement(body); |
| 555 var typeFormals = classElem.typeParameters; | 564 var typeFormals = classElem.typeParameters; |
| 556 if (typeFormals.isNotEmpty) { | 565 if (typeFormals.isNotEmpty) { |
| 557 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); | 566 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); |
| 558 } | 567 } |
| 559 | 568 |
| 560 body = <JS.Statement>[classDef]; | 569 body = <JS.Statement>[classDef]; |
| 561 _emitStaticFields(staticFields, classElem, body); | 570 _emitStaticFields(staticFields, classElem, body); |
| 562 _registerExtensionType(classElem, body); | 571 _registerExtensionType(classElem, body); |
| 563 return _statement(body); | 572 return _statement(body); |
| 564 } | 573 } |
| 565 | 574 |
| 566 JS.Expression _defineClass(ClassElement classElem, | 575 void _defineClass(ClassElement classElem, JS.Expression className, |
| 567 JS.ClassExpression classExpr, List<JS.Statement> body) { | 576 JS.ClassExpression classExpr, List<JS.Statement> body) { |
| 568 JS.Expression className; | |
| 569 if (classElem.typeParameters.isNotEmpty) { | 577 if (classElem.typeParameters.isNotEmpty) { |
| 570 // Generic classes will be defined inside a function that closes over the | 578 // Generic classes will be defined inside a function that closes over the |
| 571 // type parameter. So we can use their local variable name directly. | 579 // type parameter. So we can use their local variable name directly. |
| 572 className = classExpr.name; | |
| 573 body.add(new JS.ClassDeclaration(classExpr)); | 580 body.add(new JS.ClassDeclaration(classExpr)); |
| 574 } else { | 581 } else { |
| 575 className = _emitTopLevelName(classElem); | |
| 576 body.add(js.statement('# = #;', [className, classExpr])); | 582 body.add(js.statement('# = #;', [className, classExpr])); |
| 577 } | 583 } |
| 578 return className; | 584 } |
| 585 | |
| 586 void _emitVirtualFieldSymbols(ClassElement elem, List<JS.Statement> body) { | |
| 587 if (_virtualFieldSymbols[elem] == null) return; | |
| 588 body.addAll(_virtualFieldSymbols[elem]); | |
| 579 } | 589 } |
| 580 | 590 |
| 581 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { | 591 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { |
| 582 return typeFormals | 592 return typeFormals |
| 583 .map((t) => new JS.Identifier(t.name)) | 593 .map((t) => new JS.Identifier(t.name)) |
| 584 .toList(growable: false); | 594 .toList(growable: false); |
| 585 } | 595 } |
| 586 | 596 |
| 587 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED | 597 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED |
| 588 /// (e.g. `class Foo { i: string; }`) | 598 /// (e.g. `class Foo { i: string; }`) |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 745 [value], js.statement('{ this.# = #; }', [name, value])); | 755 [value], js.statement('{ this.# = #; }', [name, value])); |
| 746 method = new JS.Method(_elementMemberName(field.setter), fn, | 756 method = new JS.Method(_elementMemberName(field.setter), fn, |
| 747 isSetter: true); | 757 isSetter: true); |
| 748 jsMethods.add(method); | 758 jsMethods.add(method); |
| 749 } | 759 } |
| 750 } | 760 } |
| 751 } | 761 } |
| 752 return jsMethods; | 762 return jsMethods; |
| 753 } | 763 } |
| 754 | 764 |
| 755 List<JS.Method> _emitClassMethods(ClassDeclaration node, | 765 List<JS.Method> _emitClassMethods( |
| 756 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) { | 766 ClassDeclaration node, |
| 767 List<ConstructorDeclaration> ctors, | |
| 768 List<FieldDeclaration> fields, | |
| 769 JS.Expression className, | |
| 770 ClassElement classElem) { | |
|
Jennifer Messerly
2016/04/25 22:47:04
This parameter isn't needed.
See the very next li
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 757 var element = node.element; | 771 var element = node.element; |
| 758 var type = element.type; | 772 var type = element.type; |
| 759 var isObject = type.isObject; | 773 var isObject = type.isObject; |
| 760 | 774 |
| 761 // Iff no constructor is specified for a class C, it implicitly has a | 775 // Iff no constructor is specified for a class C, it implicitly has a |
| 762 // default constructor `C() : super() {}`, unless C is class Object. | 776 // default constructor `C() : super() {}`, unless C is class Object. |
| 763 var jsMethods = <JS.Method>[]; | 777 var jsMethods = <JS.Method>[]; |
| 764 if (ctors.isEmpty && !isObject) { | 778 if (ctors.isEmpty && !isObject) { |
| 765 jsMethods.add(_emitImplicitConstructor(node, fields)); | 779 jsMethods.add(_emitImplicitConstructor(node, fields)); |
| 766 } | 780 } |
| 767 | 781 |
| 768 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; | 782 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; |
| 769 var superclasses = getSuperclasses(element); | 783 var superclasses = getSuperclasses(element); |
| 770 | 784 |
| 771 bool hasIterator = false; | 785 bool hasIterator = false; |
| 772 for (var m in node.members) { | 786 for (var m in node.members) { |
| 773 if (m is ConstructorDeclaration) { | 787 if (m is ConstructorDeclaration) { |
| 774 jsMethods.add(_emitConstructor(m, type, fields, isObject)); | 788 jsMethods.add(_emitConstructor(m, type, fields, isObject)); |
| 775 } else if (m is MethodDeclaration) { | 789 } else if (m is MethodDeclaration) { |
| 776 jsMethods.add(_emitMethodDeclaration(type, m)); | 790 jsMethods.add(_emitMethodDeclaration(type, m)); |
| 777 | 791 |
| 778 if (m.element is PropertyAccessorElement) { | 792 if (m.element is PropertyAccessorElement) { |
| 779 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); | 793 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); |
| 780 } | 794 } |
| 781 | 795 |
| 782 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 796 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { |
| 783 hasIterator = true; | 797 hasIterator = true; |
| 784 jsMethods.add(_emitIterable(type)); | 798 jsMethods.add(_emitIterable(type)); |
| 785 } | 799 } |
| 786 } else if (m is FieldDeclaration && _extensionTypes.contains(element)) { | 800 } else if (m is FieldDeclaration) { |
| 787 jsMethods.addAll(_emitNativeFieldAccessors(m)); | 801 if (_extensionTypes.contains(element)) { |
| 802 jsMethods.addAll(_emitNativeFieldAccessors(m)); | |
| 803 continue; | |
| 804 } | |
| 805 if (m.isStatic) continue; | |
| 806 for (VariableDeclaration field in m.fields.variables) { | |
| 807 var propertyOverrideResult = checkForPropertyOverride( | |
| 808 field.element, superclasses, _extensionTypes); | |
| 809 if (propertyOverrideResult.foundGetter || | |
|
Jennifer Messerly
2016/04/25 22:47:04
consider: a shorter name here.
"overrideInfo" or
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 810 propertyOverrideResult.foundSetter) { | |
| 811 jsMethods.addAll( | |
| 812 _emitVirtualFieldAccessor(field, type, className, classElem)); | |
|
Jennifer Messerly
2016/04/25 22:47:04
fyi -- you probably don't need to pass classElem o
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 813 } | |
| 814 } | |
| 788 } | 815 } |
| 789 } | 816 } |
| 790 | 817 |
| 791 // If the type doesn't have an `iterator`, but claims to implement Iterable, | 818 // If the type doesn't have an `iterator`, but claims to implement Iterable, |
| 792 // we inject the adaptor method here, as it's less code size to put the | 819 // we inject the adaptor method here, as it's less code size to put the |
| 793 // helper on a parent class. This pattern is common in the core libraries | 820 // helper on a parent class. This pattern is common in the core libraries |
| 794 // (e.g. IterableMixin<E> and IterableBase<E>). | 821 // (e.g. IterableMixin<E> and IterableBase<E>). |
| 795 // | 822 // |
| 796 // (We could do this same optimization for any interface with an `iterator` | 823 // (We could do this same optimization for any interface with an `iterator` |
| 797 // method, but that's more expensive to check for, so it doesn't seem worth | 824 // method, but that's more expensive to check for, so it doesn't seem worth |
| 798 // it. The above case for an explicit `iterator` method will catch those.) | 825 // it. The above case for an explicit `iterator` method will catch those.) |
| 799 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 826 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
| 800 jsMethods.add(_emitIterable(type)); | 827 jsMethods.add(_emitIterable(type)); |
| 801 } | 828 } |
| 802 | 829 |
| 803 return jsMethods.where((m) => m != null).toList(growable: false); | 830 return jsMethods.where((m) => m != null).toList(growable: false); |
| 804 } | 831 } |
| 805 | 832 |
| 833 /// This is called whenever a derived class needs to introduce a new field, | |
| 834 /// shadowing a field or getter/setter pair on its parent. | |
| 835 /// | |
| 836 /// This is important because otherwise, trying to read or write the field | |
| 837 /// would end up calling the getter or setter, and one of those might not even | |
| 838 /// exist, resulting in a runtime error. Even if they did exist, that's the | |
| 839 /// wrong behavior if a new field was declared. | |
| 840 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field, | |
| 841 InterfaceType type, JS.Expression className, ClassElement classElem) { | |
| 842 var virtualField = _emitVirtualFieldSymbol(field, className, classElem); | |
| 843 var result = <JS.Method>[]; | |
| 844 var name = _emitMemberName(field.element.name, type: type); | |
| 845 var getter = js.call('function() { return this[#]; }', [virtualField]); | |
| 846 result.add(new JS.Method(name, getter, isGetter: true)); | |
| 847 | |
| 848 if (field.isFinal) { | |
| 849 var setter = js.call( | |
| 850 'function(value) {' | |
|
Jennifer Messerly
2016/04/25 22:47:04
style comment: triple quote style is nicer for the
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 851 ' var f = this[#];' | |
| 852 ' if (f === undefined) {' | |
|
Jennifer Messerly
2016/04/25 22:47:04
Hmmmm, I'm a little confused about what's going on
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
| 853 ' this[#] = value;' | |
| 854 ' } else {' | |
| 855 ' super[#] = value;' | |
| 856 ' }' | |
| 857 '}', | |
| 858 [virtualField, virtualField, name]); | |
| 859 result.add(new JS.Method(name, setter, isSetter: true)); | |
| 860 } else { | |
| 861 var setter = | |
| 862 js.call('function(value) { this[#] = value; }', [virtualField]); | |
| 863 result.add(new JS.Method(name, setter, isSetter: true)); | |
| 864 } | |
| 865 | |
| 866 return result; | |
| 867 } | |
| 868 | |
| 869 /// Emit a getter or setter that simply forwards to the superclass getter or | |
| 870 /// setter. This is needed because in ES6, if you only override a getter | |
| 871 /// (alternatively, a setter), then there is an implicit override of the | |
| 872 /// setter (alternatively, the getter) that does nothing. | |
| 806 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, | 873 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, |
| 807 InterfaceType type, List<ClassElement> superclasses) { | 874 InterfaceType type, List<ClassElement> superclasses) { |
| 808 var methodElement = method.element as PropertyAccessorElement; | 875 var methodElement = method.element as PropertyAccessorElement; |
| 809 var field = methodElement.variable; | 876 var field = methodElement.variable; |
| 810 if (!field.isSynthetic) return null; | 877 if (!field.isSynthetic) return null; |
| 811 var propertyOverrideResult = checkForPropertyOverride( | 878 var propertyOverrideResult = checkForPropertyOverride( |
| 812 methodElement.variable, superclasses, _extensionTypes); | 879 methodElement.variable, superclasses, _extensionTypes); |
| 813 | 880 |
| 814 // Generate a corresponding virtual getter / setter. | 881 // Generate a corresponding virtual getter / setter. |
| 815 var name = _elementMemberName(methodElement, | 882 var name = _elementMemberName(methodElement, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 904 newBaseClass = js.call('dart.global.#', [jsPeerName]); | 971 newBaseClass = js.call('dart.global.#', [jsPeerName]); |
| 905 } else if (_hasDeferredSupertype.contains(classElem)) { | 972 } else if (_hasDeferredSupertype.contains(classElem)) { |
| 906 newBaseClass = _emitTypeName(classElem.type.superclass); | 973 newBaseClass = _emitTypeName(classElem.type.superclass); |
| 907 } | 974 } |
| 908 if (newBaseClass != null) { | 975 if (newBaseClass != null) { |
| 909 body.add( | 976 body.add( |
| 910 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); | 977 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); |
| 911 } | 978 } |
| 912 } | 979 } |
| 913 | 980 |
| 914 /// Emits instance fields, if they are virtual | |
| 915 /// (in other words, they override a getter/setter pair). | |
| 916 void _emitVirtualFields( | |
| 917 ClassElement classElement, | |
| 918 List<FieldDeclaration> fields, | |
| 919 JS.Expression className, | |
| 920 List<JS.Statement> body) { | |
| 921 List<ClassElement> superclasses = getSuperclasses(classElement); | |
| 922 for (FieldDeclaration member in fields) { | |
| 923 for (VariableDeclaration field in member.fields.variables) { | |
| 924 var propertyOverrideResult = checkForPropertyOverride( | |
| 925 field.element, superclasses, _extensionTypes); | |
| 926 if (propertyOverrideResult.foundGetter || | |
| 927 propertyOverrideResult.foundSetter) { | |
| 928 body.add(_overrideField(className, field.element)); | |
| 929 } | |
| 930 } | |
| 931 } | |
| 932 } | |
| 933 | |
| 934 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, | 981 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, |
| 935 List<JS.Statement> body, JS.Expression className) { | 982 List<JS.Statement> body, JS.Expression className) { |
| 936 for (ConstructorDeclaration member in ctors) { | 983 for (ConstructorDeclaration member in ctors) { |
| 937 if (member.name != null && member.factoryKeyword == null) { | 984 if (member.name != null && member.factoryKeyword == null) { |
| 938 body.add(js.statement('dart.defineNamedConstructor(#, #);', | 985 body.add(js.statement('dart.defineNamedConstructor(#, #);', |
| 939 [className, _emitMemberName(member.name.name, isStatic: true)])); | 986 [className, _emitMemberName(member.name.name, isStatic: true)])); |
| 940 } | 987 } |
| 941 } | 988 } |
| 942 } | 989 } |
| 943 | 990 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1130 if (_extensionTypes.contains(element)) types.add(element); | 1177 if (_extensionTypes.contains(element)) types.add(element); |
| 1131 for (var m in type.mixins.reversed) { | 1178 for (var m in type.mixins.reversed) { |
| 1132 _collectExtensions(m, types); | 1179 _collectExtensions(m, types); |
| 1133 } | 1180 } |
| 1134 for (var i in type.interfaces) { | 1181 for (var i in type.interfaces) { |
| 1135 _collectExtensions(i, types); | 1182 _collectExtensions(i, types); |
| 1136 } | 1183 } |
| 1137 _collectExtensions(type.superclass, types); | 1184 _collectExtensions(type.superclass, types); |
| 1138 } | 1185 } |
| 1139 | 1186 |
| 1140 JS.Statement _overrideField(JS.Expression className, FieldElement e) { | |
| 1141 var cls = e.enclosingElement; | |
| 1142 return js.statement('dart.virtualField(#, #)', | |
| 1143 [className, _emitMemberName(e.name, type: cls.type)]); | |
| 1144 } | |
| 1145 | |
| 1146 /// Generates the implicit default constructor for class C of the form | 1187 /// Generates the implicit default constructor for class C of the form |
| 1147 /// `C() : super() {}`. | 1188 /// `C() : super() {}`. |
| 1148 JS.Method _emitImplicitConstructor( | 1189 JS.Method _emitImplicitConstructor( |
| 1149 ClassDeclaration node, List<FieldDeclaration> fields) { | 1190 ClassDeclaration node, List<FieldDeclaration> fields) { |
| 1150 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); | 1191 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); |
| 1151 | 1192 |
| 1152 // If we don't have a method body, skip this. | 1193 // If we don't have a method body, skip this. |
| 1153 var superCall = _superConstructorCall(node.element); | 1194 var superCall = _superConstructorCall(node.element); |
| 1154 if (fields.isEmpty && superCall == null) return null; | 1195 if (fields.isEmpty && superCall == null) return null; |
| 1155 | 1196 |
| (...skipping 2510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3666 return _privateNames | 3707 return _privateNames |
| 3667 .putIfAbsent(library, () => new HashMap()) | 3708 .putIfAbsent(library, () => new HashMap()) |
| 3668 .putIfAbsent(name, () { | 3709 .putIfAbsent(name, () { |
| 3669 var id = new JS.TemporaryId(name); | 3710 var id = new JS.TemporaryId(name); |
| 3670 _moduleItems.add( | 3711 _moduleItems.add( |
| 3671 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); | 3712 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); |
| 3672 return id; | 3713 return id; |
| 3673 }); | 3714 }); |
| 3674 } | 3715 } |
| 3675 | 3716 |
| 3717 JS.TemporaryId _emitVirtualFieldSymbol(VariableDeclaration field, | |
| 3718 JS.Expression className, ClassElement classElem) { | |
| 3719 return _virtualFields.putIfAbsent(field, () { | |
| 3720 var fieldName = _emitMemberName(field.element.name, | |
| 3721 type: (field.element.enclosingElement as ClassElement).type); | |
| 3722 var id = new JS.TemporaryId(field.name.name); | |
| 3723 _virtualFieldSymbols.putIfAbsent(classElem, () => <JS.Statement>[]).add(js | |
| 3724 .statement('const # = Symbol(#.name + "." + #.toString());', | |
| 3725 [id, className, fieldName])); | |
| 3726 return id; | |
| 3727 }); | |
| 3728 } | |
| 3729 | |
| 3676 bool _externalOrNative(node) => | 3730 bool _externalOrNative(node) => |
| 3677 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 3731 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 3678 | 3732 |
| 3679 FunctionBody _functionBody(node) => | 3733 FunctionBody _functionBody(node) => |
| 3680 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 3734 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| 3681 | 3735 |
| 3682 /// Returns the canonical name to refer to the Dart library. | 3736 /// Returns the canonical name to refer to the Dart library. |
| 3683 JS.Identifier emitLibraryName(LibraryElement library) { | 3737 JS.Identifier emitLibraryName(LibraryElement library) { |
| 3684 // It's either one of the libraries in this module, or it's an import. | 3738 // It's either one of the libraries in this module, or it's an import. |
| 3685 return _libraries[library] ?? | 3739 return _libraries[library] ?? |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3788 } | 3842 } |
| 3789 | 3843 |
| 3790 bool isLibraryPrefix(Expression node) => | 3844 bool isLibraryPrefix(Expression node) => |
| 3791 node is SimpleIdentifier && node.staticElement is PrefixElement; | 3845 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 3792 | 3846 |
| 3793 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 3847 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 3794 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 3848 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 3795 | 3849 |
| 3796 bool _isDartRuntime(LibraryElement l) => | 3850 bool _isDartRuntime(LibraryElement l) => |
| 3797 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 3851 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |