| 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 672 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 } | 683 } |
| 684 } | 684 } |
| 685 | 685 |
| 686 @override | 686 @override |
| 687 visitAsExpression(AsExpression node) { | 687 visitAsExpression(AsExpression node) { |
| 688 Expression fromExpr = node.expression; | 688 Expression fromExpr = node.expression; |
| 689 var from = getStaticType(fromExpr); | 689 var from = getStaticType(fromExpr); |
| 690 var to = node.type.type; | 690 var to = node.type.type; |
| 691 | 691 |
| 692 JS.Expression jsFrom = _visit(fromExpr); | 692 JS.Expression jsFrom = _visit(fromExpr); |
| 693 if (_inWhitelistCode(node)) return jsFrom; | |
| 694 | 693 |
| 695 // Skip the cast if it's not needed. | 694 // Skip the cast if it's not needed. |
| 696 if (rules.isSubtypeOf(from, to)) return jsFrom; | 695 if (rules.isSubtypeOf(from, to)) return jsFrom; |
| 697 | 696 |
| 698 // All Dart number types map to a JS double. | 697 // All Dart number types map to a JS double. |
| 699 if (_isNumberInJS(from) && _isNumberInJS(to)) { | 698 if (_isNumberInJS(from) && _isNumberInJS(to)) { |
| 700 // Make sure to check when converting to int. | 699 // Make sure to check when converting to int. |
| 701 if (from != types.intType && to == types.intType) { | 700 if (from != types.intType && to == types.intType) { |
| 702 // TODO(jmesserly): fuse this with notNull check. | 701 // TODO(jmesserly): fuse this with notNull check. |
| 703 return _callHelper('asInt(#)', jsFrom); | 702 return _callHelper('asInt(#)', jsFrom); |
| (...skipping 1667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2371 [jsParam, jsParam, _defaultParamValue(param)])); | 2370 [jsParam, jsParam, _defaultParamValue(param)])); |
| 2372 } | 2371 } |
| 2373 } | 2372 } |
| 2374 | 2373 |
| 2375 // TODO(jmesserly): various problems here, see: | 2374 // TODO(jmesserly): various problems here, see: |
| 2376 // https://github.com/dart-lang/sdk/issues/27259 | 2375 // https://github.com/dart-lang/sdk/issues/27259 |
| 2377 var paramType = | 2376 var paramType = |
| 2378 resolutionMap.elementDeclaredByFormalParameter(param).type; | 2377 resolutionMap.elementDeclaredByFormalParameter(param).type; |
| 2379 if (node is MethodDeclaration && | 2378 if (node is MethodDeclaration && |
| 2380 (resolutionMap.elementDeclaredByFormalParameter(param).isCovariant || | 2379 (resolutionMap.elementDeclaredByFormalParameter(param).isCovariant || |
| 2381 _unsoundCovariant(paramType, true)) && | 2380 _unsoundCovariant(paramType, true))) { |
| 2382 !_inWhitelistCode(node)) { | |
| 2383 var castType = _emitType(paramType, | 2381 var castType = _emitType(paramType, |
| 2384 nameType: options.nameTypeTests || options.hoistTypeTests, | 2382 nameType: options.nameTypeTests || options.hoistTypeTests, |
| 2385 hoistType: options.hoistTypeTests); | 2383 hoistType: options.hoistTypeTests); |
| 2386 body.add(js.statement('#._check(#);', [castType, jsParam])); | 2384 body.add(js.statement('#._check(#);', [castType, jsParam])); |
| 2387 } | 2385 } |
| 2388 } | 2386 } |
| 2389 return body.isEmpty ? null : _statement(body); | 2387 return body.isEmpty ? null : _statement(body); |
| 2390 } | 2388 } |
| 2391 | 2389 |
| 2392 /// Given a type [t], return whether or not t is unsoundly covariant. | 2390 /// Given a type [t], return whether or not t is unsoundly covariant. |
| (...skipping 894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3287 assert(false); | 3285 assert(false); |
| 3288 } | 3286 } |
| 3289 | 3287 |
| 3290 assert(target != null); | 3288 assert(target != null); |
| 3291 | 3289 |
| 3292 if (target is SuperExpression) { | 3290 if (target is SuperExpression) { |
| 3293 return _emitSetSuper(lhs, target, id, rhs); | 3291 return _emitSetSuper(lhs, target, id, rhs); |
| 3294 } | 3292 } |
| 3295 | 3293 |
| 3296 if (target != null && isDynamicInvoke(target)) { | 3294 if (target != null && isDynamicInvoke(target)) { |
| 3297 if (_inWhitelistCode(lhs)) { | |
| 3298 var vars = <JS.MetaLetVariable, JS.Expression>{}; | |
| 3299 var l = _visit(_bindValue(vars, 'l', target)); | |
| 3300 var name = _emitMemberName(id.name); | |
| 3301 return new JS.MetaLet(vars, [ | |
| 3302 js.call('(#[(#[#._extensionType]) ? #[#] : #] = #)', [ | |
| 3303 l, | |
| 3304 l, | |
| 3305 _runtimeModule, | |
| 3306 _extensionSymbolsModule, | |
| 3307 name, | |
| 3308 name, | |
| 3309 _visit(rhs) | |
| 3310 ]) | |
| 3311 ]); | |
| 3312 } | |
| 3313 return _callHelper('#(#, #, #)', [ | 3295 return _callHelper('#(#, #, #)', [ |
| 3314 _emitDynamicOperationName('dput'), | 3296 _emitDynamicOperationName('dput'), |
| 3315 _visit(target), | 3297 _visit(target), |
| 3316 _emitMemberName(id.name), | 3298 _emitMemberName(id.name), |
| 3317 _visit(rhs) | 3299 _visit(rhs) |
| 3318 ]); | 3300 ]); |
| 3319 } | 3301 } |
| 3320 | 3302 |
| 3321 var accessor = id.staticElement; | 3303 var accessor = id.staticElement; |
| 3322 var element = | 3304 var element = |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3610 List<JS.Expression> typeArgs) { | 3592 List<JS.Expression> typeArgs) { |
| 3611 var type = getStaticType(target); | 3593 var type = getStaticType(target); |
| 3612 var element = node.methodName.staticElement; | 3594 var element = node.methodName.staticElement; |
| 3613 bool isStatic = element is ExecutableElement && element.isStatic; | 3595 bool isStatic = element is ExecutableElement && element.isStatic; |
| 3614 var name = node.methodName.name; | 3596 var name = node.methodName.name; |
| 3615 var memberName = | 3597 var memberName = |
| 3616 _emitMemberName(name, type: type, isStatic: isStatic, element: element); | 3598 _emitMemberName(name, type: type, isStatic: isStatic, element: element); |
| 3617 | 3599 |
| 3618 JS.Expression jsTarget = _emitTarget(target, element, isStatic); | 3600 JS.Expression jsTarget = _emitTarget(target, element, isStatic); |
| 3619 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { | 3601 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { |
| 3620 if (_inWhitelistCode(target)) { | |
| 3621 var vars = <JS.MetaLetVariable, JS.Expression>{}; | |
| 3622 var l = _visit(_bindValue(vars, 'l', target)); | |
| 3623 jsTarget = new JS.MetaLet(vars, [ | |
| 3624 js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [ | |
| 3625 l, | |
| 3626 l, | |
| 3627 _runtimeModule, | |
| 3628 _extensionSymbolsModule, | |
| 3629 memberName, | |
| 3630 memberName, | |
| 3631 l | |
| 3632 ]) | |
| 3633 ]); | |
| 3634 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | |
| 3635 return new JS.Call(jsTarget, args); | |
| 3636 } | |
| 3637 if (typeArgs != null) { | 3602 if (typeArgs != null) { |
| 3638 return _callHelper('#(#, #, #, #)', [ | 3603 return _callHelper('#(#, #, #, #)', [ |
| 3639 _emitDynamicOperationName('dgsend'), | 3604 _emitDynamicOperationName('dgsend'), |
| 3640 jsTarget, | 3605 jsTarget, |
| 3641 new JS.ArrayInitializer(typeArgs), | 3606 new JS.ArrayInitializer(typeArgs), |
| 3642 memberName, | 3607 memberName, |
| 3643 args | 3608 args |
| 3644 ]); | 3609 ]); |
| 3645 } else { | 3610 } else { |
| 3646 return _callHelper('#(#, #, #)', | 3611 return _callHelper('#(#, #, #)', |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3658 return new JS.Call(jsTarget, args); | 3623 return new JS.Call(jsTarget, args); |
| 3659 } | 3624 } |
| 3660 | 3625 |
| 3661 JS.Expression _emitDynamicInvoke( | 3626 JS.Expression _emitDynamicInvoke( |
| 3662 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { | 3627 InvocationExpression node, JS.Expression fn, List<JS.Expression> args) { |
| 3663 var typeArgs = _emitInvokeTypeArguments(node); | 3628 var typeArgs = _emitInvokeTypeArguments(node); |
| 3664 if (typeArgs != null) { | 3629 if (typeArgs != null) { |
| 3665 return _callHelper( | 3630 return _callHelper( |
| 3666 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); | 3631 'dgcall(#, #, #)', [fn, new JS.ArrayInitializer(typeArgs), args]); |
| 3667 } else { | 3632 } else { |
| 3668 if (_inWhitelistCode(node, isCall: true)) { | |
| 3669 return new JS.Call(fn, args); | |
| 3670 } | |
| 3671 return _callHelper('dcall(#, #)', [fn, args]); | 3633 return _callHelper('dcall(#, #)', [fn, args]); |
| 3672 } | 3634 } |
| 3673 } | 3635 } |
| 3674 | 3636 |
| 3675 /// Emits a function call, to a top-level function, local function, or | 3637 /// Emits a function call, to a top-level function, local function, or |
| 3676 /// an expression. | 3638 /// an expression. |
| 3677 JS.Expression _emitFunctionCall(InvocationExpression node, | 3639 JS.Expression _emitFunctionCall(InvocationExpression node, |
| 3678 [Expression function]) { | 3640 [Expression function]) { |
| 3679 if (function == null) { | 3641 if (function == null) { |
| 3680 function = node.function; | 3642 function = node.function; |
| (...skipping 1284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4965 | 4927 |
| 4966 JS.LiteralString _emitDynamicOperationName(String name) => | 4928 JS.LiteralString _emitDynamicOperationName(String name) => |
| 4967 js.string(options.replCompile ? '${name}Repl' : name); | 4929 js.string(options.replCompile ? '${name}Repl' : name); |
| 4968 | 4930 |
| 4969 JS.Expression _emitAccessInternal(Expression target, Element member, | 4931 JS.Expression _emitAccessInternal(Expression target, Element member, |
| 4970 String memberName, List<JS.Expression> typeArgs) { | 4932 String memberName, List<JS.Expression> typeArgs) { |
| 4971 bool isStatic = member is ClassMemberElement && member.isStatic; | 4933 bool isStatic = member is ClassMemberElement && member.isStatic; |
| 4972 var name = _emitMemberName(memberName, | 4934 var name = _emitMemberName(memberName, |
| 4973 type: getStaticType(target), isStatic: isStatic, element: member); | 4935 type: getStaticType(target), isStatic: isStatic, element: member); |
| 4974 if (isDynamicInvoke(target)) { | 4936 if (isDynamicInvoke(target)) { |
| 4975 if (_inWhitelistCode(target)) { | |
| 4976 var vars = <JS.MetaLetVariable, JS.Expression>{}; | |
| 4977 var l = _visit(_bindValue(vars, 'l', target)); | |
| 4978 return new JS.MetaLet(vars, [ | |
| 4979 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', | |
| 4980 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) | |
| 4981 ]); | |
| 4982 } | |
| 4983 return _callHelper('#(#, #)', | 4937 return _callHelper('#(#, #)', |
| 4984 [_emitDynamicOperationName('dload'), _visit(target), name]); | 4938 [_emitDynamicOperationName('dload'), _visit(target), name]); |
| 4985 } | 4939 } |
| 4986 | 4940 |
| 4987 var jsTarget = _emitTarget(target, member, isStatic); | 4941 var jsTarget = _emitTarget(target, member, isStatic); |
| 4988 bool isSuper = jsTarget is JS.Super; | 4942 bool isSuper = jsTarget is JS.Super; |
| 4989 if (isSuper && | 4943 if (isSuper && |
| 4990 !member.isSynthetic && | 4944 !member.isSynthetic && |
| 4991 member is FieldElementImpl && | 4945 member is FieldElementImpl && |
| 4992 !virtualFields.isVirtual(member)) { | 4946 !virtualFields.isVirtual(member)) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5029 /// Emits a generic send, like an operator method. | 4983 /// Emits a generic send, like an operator method. |
| 5030 /// | 4984 /// |
| 5031 /// **Please note** this function does not support method invocation syntax | 4985 /// **Please note** this function does not support method invocation syntax |
| 5032 /// `obj.name(args)` because that could be a getter followed by a call. | 4986 /// `obj.name(args)` because that could be a getter followed by a call. |
| 5033 /// See [visitMethodInvocation]. | 4987 /// See [visitMethodInvocation]. |
| 5034 JS.Expression _emitSend( | 4988 JS.Expression _emitSend( |
| 5035 Expression target, String name, List<Expression> args) { | 4989 Expression target, String name, List<Expression> args) { |
| 5036 var type = getStaticType(target); | 4990 var type = getStaticType(target); |
| 5037 var memberName = _emitMemberName(name, type: type); | 4991 var memberName = _emitMemberName(name, type: type); |
| 5038 if (isDynamicInvoke(target)) { | 4992 if (isDynamicInvoke(target)) { |
| 5039 if (_inWhitelistCode(target)) { | |
| 5040 var vars = <JS.MetaLetVariable, JS.Expression>{}; | |
| 5041 var l = _visit(_bindValue(vars, 'l', target)); | |
| 5042 return new JS.MetaLet(vars, [ | |
| 5043 js.call('(#[(#[#._extensionType]) ? #[#] : #]).call(#, #)', [ | |
| 5044 l, | |
| 5045 l, | |
| 5046 _runtimeModule, | |
| 5047 _extensionSymbolsModule, | |
| 5048 memberName, | |
| 5049 memberName, | |
| 5050 l, | |
| 5051 _visitList(args) | |
| 5052 ]) | |
| 5053 ]); | |
| 5054 } | |
| 5055 // dynamic dispatch | 4993 // dynamic dispatch |
| 5056 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name]; | 4994 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name]; |
| 5057 if (dynamicHelper != null) { | 4995 if (dynamicHelper != null) { |
| 5058 return _callHelper('$dynamicHelper(#, #)', | 4996 return _callHelper('$dynamicHelper(#, #)', |
| 5059 [_visit(target) as JS.Expression, _visitList(args)]); | 4997 [_visit(target) as JS.Expression, _visitList(args)]); |
| 5060 } else { | 4998 } else { |
| 5061 return _callHelper( | 4999 return _callHelper( |
| 5062 'dsend(#, #, #)', [_visit(target), memberName, _visitList(args)]); | 5000 'dsend(#, #, #)', [_visit(target), memberName, _visitList(args)]); |
| 5063 } | 5001 } |
| 5064 } | 5002 } |
| (...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5830 | 5768 |
| 5831 JS.Statement _callHelperStatement(String code, args) { | 5769 JS.Statement _callHelperStatement(String code, args) { |
| 5832 if (args is List) { | 5770 if (args is List) { |
| 5833 args.insert(0, _runtimeModule); | 5771 args.insert(0, _runtimeModule); |
| 5834 } else { | 5772 } else { |
| 5835 args = [_runtimeModule, args]; | 5773 args = [_runtimeModule, args]; |
| 5836 } | 5774 } |
| 5837 return js.statement('#.$code', args); | 5775 return js.statement('#.$code', args); |
| 5838 } | 5776 } |
| 5839 | 5777 |
| 5840 // TODO(kevmoo): https://github.com/dart-lang/sdk/issues/27255 | |
| 5841 // TODO(kevmoo): Remove once pkg/angular2 has moved to the new compiler | |
| 5842 // See https://github.com/dart-lang/angular2/issues/48 | |
| 5843 /// Temporary workaround *cough* total hack *cough*. | |
| 5844 /// | |
| 5845 /// Maps whitelisted files to a list of whitelisted methods | |
| 5846 /// within the file. | |
| 5847 /// | |
| 5848 /// If the value is null, the entire file is whitelisted. | |
| 5849 /// | |
| 5850 static const Map<String, List<String>> _uncheckedWhitelist = const { | |
| 5851 'dom_renderer.dart': const ['moveNodesAfterSibling'], | |
| 5852 'template_ref.dart': const ['createEmbeddedView'], | |
| 5853 'ng_class.dart': const ['_applyIterableChanges'], | |
| 5854 'ng_for.dart': const ['_bulkRemove', '_bulkInsert'], | |
| 5855 'view_container_ref.dart': const ['createEmbeddedView'], | |
| 5856 'default_iterable_differ.dart': null, | |
| 5857 }; | |
| 5858 | |
| 5859 static Set<String> _uncheckedWhitelistCalls = new Set() | |
| 5860 ..add('ng_zone_impl.dart') | |
| 5861 ..add('stack_zone_specification.dart') | |
| 5862 ..add('view_manager.dart') | |
| 5863 ..add('view.dart'); | |
| 5864 | |
| 5865 bool _inWhitelistCode(AstNode node, {isCall: false}) { | |
| 5866 if (!options.useAngular2Whitelist) return false; | |
| 5867 var path = currentElement.source.fullName; | |
| 5868 var filename = path.split("/").last; | |
| 5869 if (_uncheckedWhitelist.containsKey(filename)) { | |
| 5870 var whitelisted = _uncheckedWhitelist[filename]; | |
| 5871 if (whitelisted == null) return true; | |
| 5872 var enclosing = node; | |
| 5873 while (enclosing != null && | |
| 5874 !(enclosing is ClassMember || enclosing is FunctionDeclaration)) { | |
| 5875 enclosing = enclosing.parent; | |
| 5876 } | |
| 5877 String name = (enclosing as dynamic)?.element?.name; | |
| 5878 if (name != null) { | |
| 5879 return whitelisted.contains(name); | |
| 5880 } | |
| 5881 } | |
| 5882 | |
| 5883 // Dynamic calls are less risky so there is no need to whitelist at the | |
| 5884 // method level. | |
| 5885 if (isCall && _uncheckedWhitelistCalls.contains(filename)) return true; | |
| 5886 | |
| 5887 return path.endsWith(".template.dart"); | |
| 5888 } | |
| 5889 | |
| 5890 _unreachable(AstNode node) { | 5778 _unreachable(AstNode node) { |
| 5891 throw new UnsupportedError( | 5779 throw new UnsupportedError( |
| 5892 'tried to generate an unreachable node: `$node`'); | 5780 'tried to generate an unreachable node: `$node`'); |
| 5893 } | 5781 } |
| 5894 | 5782 |
| 5895 /// Unused, see methods for emitting declarations. | 5783 /// Unused, see methods for emitting declarations. |
| 5896 @override | 5784 @override |
| 5897 visitAnnotation(node) => _unreachable(node); | 5785 visitAnnotation(node) => _unreachable(node); |
| 5898 | 5786 |
| 5899 /// Unused, see [_emitArgumentList]. | 5787 /// Unused, see [_emitArgumentList]. |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6103 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5991 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 6104 var prefix = targetIdentifier.staticElement as PrefixElement; | 5992 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 6105 | 5993 |
| 6106 // The library the prefix is referring to must come from a deferred import. | 5994 // The library the prefix is referring to must come from a deferred import. |
| 6107 var containingLibrary = resolutionMap | 5995 var containingLibrary = resolutionMap |
| 6108 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5996 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
| 6109 .library; | 5997 .library; |
| 6110 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5998 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 6111 return imports.length == 1 && imports[0].isDeferred; | 5999 return imports.length == 1 && imports[0].isDeferred; |
| 6112 } | 6000 } |
| OLD | NEW |