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 | 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 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 var libraryPrefix = <String>[]; | 317 var libraryPrefix = <String>[]; |
| 318 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 318 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
| 319 libraryPrefix.addAll(libraryJSName.split('.')); | 319 libraryPrefix.addAll(libraryJSName.split('.')); |
| 320 } | 320 } |
| 321 | 321 |
| 322 String elementJSName; | 322 String elementJSName; |
| 323 if (findAnnotation(e, isPublicJSAnnotation) != null) { | 323 if (findAnnotation(e, isPublicJSAnnotation) != null) { |
| 324 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; | 324 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; |
| 325 } | 325 } |
| 326 | 326 |
| 327 if (e is TopLevelVariableElement && | 327 if (e is TopLevelVariableElement) { |
| 328 e.getter != null && | 328 elementJSName = _jsInteropStaticMemberName(e); |
| 329 (e.getter.isExternal || | |
| 330 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | |
| 331 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | |
| 332 } | 329 } |
| 333 if (elementJSName == null) return null; | 330 if (elementJSName == null) return null; |
| 334 | 331 |
| 335 var elementJSParts = <String>[]; | 332 var elementJSParts = <String>[]; |
| 336 if (elementJSName.isNotEmpty) { | 333 if (elementJSName.isNotEmpty) { |
| 337 elementJSParts.addAll(elementJSName.split('.')); | 334 elementJSParts.addAll(elementJSName.split('.')); |
| 338 } else { | 335 } else { |
| 339 elementJSParts.add(e.name); | 336 elementJSParts.add(e.name); |
| 340 } | 337 } |
| 341 | 338 |
| 342 return libraryPrefix..addAll(elementJSParts); | 339 return libraryPrefix..addAll(elementJSParts); |
| 343 } | 340 } |
| 344 | 341 |
| 345 JS.Expression _emitJSInterop(Element e) { | 342 JS.Expression _emitJSInterop(Element e) { |
| 346 var jsName = _getJSName(e); | 343 var jsName = _getJSName(e); |
| 347 if (jsName == null) return null; | 344 if (jsName == null) return null; |
| 348 var fullName = ['global']..addAll(jsName); | 345 var fullName = ['global']..addAll(jsName); |
| 349 JS.Expression access = _runtimeModule; | 346 JS.Expression access = _runtimeModule; |
| 350 for (var part in fullName) { | 347 for (var part in fullName) { |
| 351 access = new JS.PropertyAccess(access, js.string(part)); | 348 access = new JS.PropertyAccess(access, js.string(part)); |
| 352 } | 349 } |
| 353 return access; | 350 return access; |
| 354 } | 351 } |
| 355 | 352 |
| 353 String _jsInteropStaticMemberName(Element e, {String name}) { | |
| 354 if (e == null || e.library == null || | |
| 355 findAnnotation(e.library, isPublicJSAnnotation) == null) { | |
| 356 return null; | |
| 357 } | |
| 358 if (e is PropertyInducingElement) { | |
| 359 // Assume properties have consistent JS names for getters and setters. | |
| 360 return _jsInteropStaticMemberName(e.getter, name: e.name) ?? | |
| 361 _jsInteropStaticMemberName(e.setter, name: e.name); | |
| 362 } | |
| 363 if (e is ExecutableElement && | |
| 364 e.isExternal && | |
| 365 findAnnotation(e, isPublicJSAnnotation) != null) { | |
| 366 return getAnnotationName(e, isPublicJSAnnotation) ?? name ?? e.name; | |
| 367 } | |
| 368 return null; | |
| 369 } | |
| 370 | |
| 371 JS.Expression _emitJSInteropStaticMemberName(Element e) { | |
| 372 var name = _jsInteropStaticMemberName(e); | |
| 373 if (name == null) return null; | |
| 374 // We do not support statics names with JS annotations containing dots. | |
| 375 // See https://github.com/dart-lang/sdk/issues/27926 | |
| 376 assert(!name.contains('.')); | |
|
Jennifer Messerly
2016/11/29 20:54:52
This should be an error or a throw, rather than an
Jacob
2016/11/29 21:37:33
Done.
| |
| 377 return js.string(name); | |
| 378 } | |
| 379 | |
| 356 /// Flattens blocks in [items] to a single list. | 380 /// Flattens blocks in [items] to a single list. |
| 357 /// | 381 /// |
| 358 /// This will not flatten blocks that are marked as being scopes. | 382 /// This will not flatten blocks that are marked as being scopes. |
| 359 void _copyAndFlattenBlocks( | 383 void _copyAndFlattenBlocks( |
| 360 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { | 384 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { |
| 361 for (var item in items) { | 385 for (var item in items) { |
| 362 if (item is JS.Block && !item.isScope) { | 386 if (item is JS.Block && !item.isScope) { |
| 363 _copyAndFlattenBlocks(result, item.statements); | 387 _copyAndFlattenBlocks(result, item.statements); |
| 364 } else { | 388 } else { |
| 365 result.add(item); | 389 result.add(item); |
| (...skipping 2332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2698 return _emitTopLevelName(element); | 2722 return _emitTopLevelName(element); |
| 2699 } | 2723 } |
| 2700 | 2724 |
| 2701 var name = element.name; | 2725 var name = element.name; |
| 2702 | 2726 |
| 2703 // Unqualified class member. This could mean implicit-this, or implicit | 2727 // Unqualified class member. This could mean implicit-this, or implicit |
| 2704 // call to a static from the same class. | 2728 // call to a static from the same class. |
| 2705 if (element is ClassMemberElement && element is! ConstructorElement) { | 2729 if (element is ClassMemberElement && element is! ConstructorElement) { |
| 2706 bool isStatic = element.isStatic; | 2730 bool isStatic = element.isStatic; |
| 2707 var type = element.enclosingElement.type; | 2731 var type = element.enclosingElement.type; |
| 2708 var member = _emitMemberName(name, isStatic: isStatic, type: type); | 2732 var member = _emitMemberName(name, |
| 2733 isStatic: isStatic, type: type, element: element); | |
| 2709 | 2734 |
| 2710 if (isStatic) { | 2735 if (isStatic) { |
| 2711 var dynType = _emitStaticAccess(type); | 2736 var dynType = _emitStaticAccess(type); |
| 2712 return new JS.PropertyAccess(dynType, member); | 2737 return new JS.PropertyAccess(dynType, member); |
| 2713 } | 2738 } |
| 2714 | 2739 |
| 2715 // For instance members, we add implicit-this. | 2740 // For instance members, we add implicit-this. |
| 2716 // For method tear-offs, we ensure it's a bound method. | 2741 // For method tear-offs, we ensure it's a bound method. |
| 2717 var tearOff = element is MethodElement && !inInvocationContext(node); | 2742 var tearOff = element is MethodElement && !inInvocationContext(node); |
| 2718 if (tearOff) return _callHelper('bind(this, #)', member); | 2743 if (tearOff) return _callHelper('bind(this, #)', member); |
| (...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3264 | 3289 |
| 3265 /// Emits assignment to a static field element or property. | 3290 /// Emits assignment to a static field element or property. |
| 3266 JS.Expression _emitSetStaticProperty( | 3291 JS.Expression _emitSetStaticProperty( |
| 3267 Expression lhs, Element element, Expression rhs) { | 3292 Expression lhs, Element element, Expression rhs) { |
| 3268 // For static methods, we add the raw type name, without generics or | 3293 // For static methods, we add the raw type name, without generics or |
| 3269 // library prefix. We don't need those because static calls can't use | 3294 // library prefix. We don't need those because static calls can't use |
| 3270 // the generic type. | 3295 // the generic type. |
| 3271 ClassElement classElement = element.enclosingElement; | 3296 ClassElement classElement = element.enclosingElement; |
| 3272 var type = classElement.type; | 3297 var type = classElement.type; |
| 3273 var dynType = _emitStaticAccess(type); | 3298 var dynType = _emitStaticAccess(type); |
| 3274 var member = _emitMemberName(element.name, isStatic: true, type: type); | 3299 var member = _emitMemberName(element.name, |
| 3300 isStatic: true, type: type, element: element); | |
| 3275 return _visit(rhs).toAssignExpression( | 3301 return _visit(rhs).toAssignExpression( |
| 3276 annotate(new JS.PropertyAccess(dynType, member), lhs)); | 3302 annotate(new JS.PropertyAccess(dynType, member), lhs)); |
| 3277 } | 3303 } |
| 3278 | 3304 |
| 3279 /// Emits an assignment to the [element] property of instance referenced by | 3305 /// Emits an assignment to the [element] property of instance referenced by |
| 3280 /// [jsTarget]. | 3306 /// [jsTarget]. |
| 3281 JS.Expression _emitWriteInstanceProperty(Expression lhs, | 3307 JS.Expression _emitWriteInstanceProperty(Expression lhs, |
| 3282 JS.Expression jsTarget, Element element, JS.Expression value) { | 3308 JS.Expression jsTarget, Element element, JS.Expression value) { |
| 3283 String memberName = element.name; | 3309 String memberName = element.name; |
| 3284 var type = (element.enclosingElement as ClassElement).type; | 3310 var type = (element.enclosingElement as ClassElement).type; |
| 3285 var name = _emitMemberName(memberName, type: type); | 3311 var name = _emitMemberName(memberName, type: type, element: element); |
| 3286 return value.toAssignExpression( | 3312 return value.toAssignExpression( |
| 3287 annotate(new JS.PropertyAccess(jsTarget, name), lhs)); | 3313 annotate(new JS.PropertyAccess(jsTarget, name), lhs)); |
| 3288 } | 3314 } |
| 3289 | 3315 |
| 3290 JS.Expression _emitSetSuper(Expression lhs, SuperExpression target, | 3316 JS.Expression _emitSetSuper(Expression lhs, SuperExpression target, |
| 3291 SimpleIdentifier id, Expression rhs) { | 3317 SimpleIdentifier id, Expression rhs) { |
| 3292 // TODO(sra): Determine whether and access helper is required for the | 3318 // TODO(sra): Determine whether and access helper is required for the |
| 3293 // setter. For now fall back on the r-value path. | 3319 // setter. For now fall back on the r-value path. |
| 3294 return _visit(rhs).toAssignExpression(_visit(lhs)); | 3320 return _visit(rhs).toAssignExpression(_visit(lhs)); |
| 3295 } | 3321 } |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3423 | 3449 |
| 3424 JS.Expression _emitTarget(Expression target, Element element, bool isStatic) { | 3450 JS.Expression _emitTarget(Expression target, Element element, bool isStatic) { |
| 3425 if (isStatic) { | 3451 if (isStatic) { |
| 3426 if (element is ConstructorElement) { | 3452 if (element is ConstructorElement) { |
| 3427 return _emitConstructorAccess(element.enclosingElement.type); | 3453 return _emitConstructorAccess(element.enclosingElement.type); |
| 3428 } | 3454 } |
| 3429 if (element is ExecutableElement) { | 3455 if (element is ExecutableElement) { |
| 3430 return _emitStaticAccess( | 3456 return _emitStaticAccess( |
| 3431 (element.enclosingElement as ClassElement).type); | 3457 (element.enclosingElement as ClassElement).type); |
| 3432 } | 3458 } |
| 3459 if (element is FieldElement) { | |
| 3460 var enclosingElement = element.enclosingElement; | |
| 3461 if (enclosingElement is ClassElement) { | |
|
Jennifer Messerly
2016/11/29 20:54:52
the "is" check is unnecessary -- FieldElement is a
Jacob
2016/11/29 21:37:33
Surprised I ever thought that is check was needed.
| |
| 3462 return _emitStaticAccess(enclosingElement.type); | |
| 3463 } | |
| 3464 } | |
| 3433 } | 3465 } |
| 3434 return _visit(target); | 3466 return _visit(target); |
| 3435 } | 3467 } |
| 3436 | 3468 |
| 3437 /// Emits a (possibly generic) instance method call. | 3469 /// Emits a (possibly generic) instance, or static method call. |
| 3438 JS.Expression _emitMethodCallInternal( | 3470 JS.Expression _emitMethodCallInternal( |
| 3439 Expression target, | 3471 Expression target, |
| 3440 MethodInvocation node, | 3472 MethodInvocation node, |
| 3441 List<JS.Expression> args, | 3473 List<JS.Expression> args, |
| 3442 List<JS.Expression> typeArgs) { | 3474 List<JS.Expression> typeArgs) { |
| 3443 var type = getStaticType(target); | 3475 var type = getStaticType(target); |
| 3444 var name = node.methodName.name; | |
| 3445 var element = node.methodName.staticElement; | 3476 var element = node.methodName.staticElement; |
| 3446 bool isStatic = element is ExecutableElement && element.isStatic; | 3477 bool isStatic = element is ExecutableElement && element.isStatic; |
| 3447 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); | 3478 var name = node.methodName.name; |
| 3479 var memberName = | |
| 3480 _emitMemberName(name, type: type, isStatic: isStatic, element: element); | |
| 3448 | 3481 |
| 3449 JS.Expression jsTarget = _emitTarget(target, element, isStatic); | 3482 JS.Expression jsTarget = _emitTarget(target, element, isStatic); |
| 3450 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { | 3483 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { |
| 3451 if (_inWhitelistCode(target)) { | 3484 if (_inWhitelistCode(target)) { |
| 3452 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3485 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
| 3453 var l = _visit(_bindValue(vars, 'l', target)); | 3486 var l = _visit(_bindValue(vars, 'l', target)); |
| 3454 jsTarget = new JS.MetaLet(vars, [ | 3487 jsTarget = new JS.MetaLet(vars, [ |
| 3455 js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [ | 3488 js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [ |
| 3456 l, | 3489 l, |
| 3457 l, | 3490 l, |
| (...skipping 1342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4800 return _emitFunctionTypeArguments(type, instantiated); | 4833 return _emitFunctionTypeArguments(type, instantiated); |
| 4801 } | 4834 } |
| 4802 | 4835 |
| 4803 JS.LiteralString _emitDynamicOperationName(String name) => | 4836 JS.LiteralString _emitDynamicOperationName(String name) => |
| 4804 js.string(options.replCompile ? '${name}Repl' : name); | 4837 js.string(options.replCompile ? '${name}Repl' : name); |
| 4805 | 4838 |
| 4806 JS.Expression _emitAccessInternal(Expression target, Element member, | 4839 JS.Expression _emitAccessInternal(Expression target, Element member, |
| 4807 String memberName, List<JS.Expression> typeArgs) { | 4840 String memberName, List<JS.Expression> typeArgs) { |
| 4808 bool isStatic = member is ClassMemberElement && member.isStatic; | 4841 bool isStatic = member is ClassMemberElement && member.isStatic; |
| 4809 var name = _emitMemberName(memberName, | 4842 var name = _emitMemberName(memberName, |
| 4810 type: getStaticType(target), isStatic: isStatic); | 4843 type: getStaticType(target), isStatic: isStatic, element: member); |
| 4811 if (isDynamicInvoke(target)) { | 4844 if (isDynamicInvoke(target)) { |
| 4812 if (_inWhitelistCode(target)) { | 4845 if (_inWhitelistCode(target)) { |
| 4813 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 4846 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
| 4814 var l = _visit(_bindValue(vars, 'l', target)); | 4847 var l = _visit(_bindValue(vars, 'l', target)); |
| 4815 return new JS.MetaLet(vars, [ | 4848 return new JS.MetaLet(vars, [ |
| 4816 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', | 4849 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', |
| 4817 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) | 4850 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) |
| 4818 ]); | 4851 ]); |
| 4819 } | 4852 } |
| 4820 return _callHelper('#(#, #)', | 4853 return _callHelper('#(#, #)', |
| (...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5419 /// | 5452 /// |
| 5420 /// This follows the same pattern as ECMAScript 6 Map: | 5453 /// This follows the same pattern as ECMAScript 6 Map: |
| 5421 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> | 5454 /// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ Objects/Map> |
| 5422 /// | 5455 /// |
| 5423 /// Unary minus looks like: `x._negate()`. | 5456 /// Unary minus looks like: `x._negate()`. |
| 5424 /// | 5457 /// |
| 5425 /// Equality is a bit special, it is generated via the Dart `equals` runtime | 5458 /// Equality is a bit special, it is generated via the Dart `equals` runtime |
| 5426 /// helper, that checks for null. The user defined method is called '=='. | 5459 /// helper, that checks for null. The user defined method is called '=='. |
| 5427 /// | 5460 /// |
| 5428 JS.Expression _emitMemberName(String name, | 5461 JS.Expression _emitMemberName(String name, |
| 5429 {DartType type, bool isStatic: false, bool useExtension}) { | 5462 {DartType type, |
| 5430 // Static members skip the rename steps. | 5463 bool isStatic: false, |
| 5431 if (isStatic) return _propertyName(name); | 5464 bool useExtension, |
| 5465 Element element}) { | |
| 5466 // Static members skip the rename steps and may require JS interop renames. | |
| 5467 if (isStatic) { | |
| 5468 return _emitJSInteropStaticMemberName(element) ?? _propertyName(name); | |
| 5469 } | |
| 5432 | 5470 |
| 5433 if (name.startsWith('_')) { | 5471 if (name.startsWith('_')) { |
| 5434 return _emitPrivateNameSymbol(currentLibrary, name); | 5472 return _emitPrivateNameSymbol(currentLibrary, name); |
| 5435 } | 5473 } |
| 5436 | 5474 |
| 5437 // When generating synthetic names, we use _ as the prefix, since Dart names | 5475 // When generating synthetic names, we use _ as the prefix, since Dart names |
| 5438 // won't have this (eliminated above), nor will static names reach here. | 5476 // won't have this (eliminated above), nor will static names reach here. |
| 5439 switch (name) { | 5477 switch (name) { |
| 5440 case '[]': | 5478 case '[]': |
| 5441 name = '_get'; | 5479 name = '_get'; |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5717 var targetIdentifier = target as SimpleIdentifier; | 5755 var targetIdentifier = target as SimpleIdentifier; |
| 5718 | 5756 |
| 5719 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5757 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5720 var prefix = targetIdentifier.staticElement as PrefixElement; | 5758 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5721 | 5759 |
| 5722 // The library the prefix is referring to must come from a deferred import. | 5760 // The library the prefix is referring to must come from a deferred import. |
| 5723 var containingLibrary = (target.root as CompilationUnit).element.library; | 5761 var containingLibrary = (target.root as CompilationUnit).element.library; |
| 5724 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5762 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5725 return imports.length == 1 && imports[0].isDeferred; | 5763 return imports.length == 1 && imports[0].isDeferred; |
| 5726 } | 5764 } |
| OLD | NEW |