Index: lib/src/codegen/js_codegen.dart |
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart |
index 9650a36306b195dc94a98398d8b63c6e0951ea0b..2280bbd061bac151a8a4985d9b31a3d9a240ff60 100644 |
--- a/lib/src/codegen/js_codegen.dart |
+++ b/lib/src/codegen/js_codegen.dart |
@@ -8,6 +8,7 @@ import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
import 'package:analyzer/src/generated/constant.dart'; |
import 'package:analyzer/src/generated/element.dart'; |
+import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
import 'package:analyzer/src/generated/scanner.dart' |
show StringToken, Token, TokenType; |
@@ -428,9 +429,17 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
String jsPeerName; |
var jsPeer = findAnnotation(classElem, isJsPeerInterface); |
+ // Only look at "Native" annotations on registered extension types. |
+ // E.g., we're current ignoring the ones in dart:html. |
+ if (jsPeer == null && _extensionTypes.contains(classElem)) { |
+ jsPeer = findAnnotation(classElem, isNativeAnnotation); |
+ } |
if (jsPeer != null) { |
jsPeerName = |
getConstantField(jsPeer, 'name', types.stringType)?.toStringValue(); |
+ if (jsPeerName.contains(',')) { |
+ jsPeerName = jsPeerName.split(',')[0]; |
+ } |
} |
var body = _finishClassMembers(classElem, classExpr, ctors, fields, |
@@ -1274,14 +1283,39 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
} |
JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { |
- if (node.isAbstract || _externalOrNative(node)) { |
+ if (node.isAbstract) { |
return null; |
} |
var params = _visit(node.parameters) as List<JS.Parameter>; |
if (params == null) params = <JS.Parameter>[]; |
- JS.Fun fn = _emitFunctionBody(params, node.body); |
+ JS.Fun fn; |
+ if (_externalOrNative(node)) { |
+ if (node.isStatic) { |
Jennifer Messerly
2016/02/10 00:20:30
Perhaps factor this out into _emitNativeFunctionBo
vsm
2016/02/11 22:36:06
Done.
|
+ // TODO(vsm): Do we need to handle this case? |
+ return null; |
+ } |
+ |
+ String name = node.name.name; |
+ var annotation = findAnnotation(node.element, isJsName); |
+ if (annotation != null) { |
+ name = getConstantField(annotation, 'name', types.stringType) |
+ ?.toStringValue(); |
+ } |
+ if (node.isGetter) { |
+ fn = new JS.Fun(params, js.statement('{ return this.#; }', [name])); |
+ } else if (node.isSetter) { |
+ fn = new JS.Fun( |
+ params, js.statement('{ this.# = #; }', [name, params.last])); |
+ } else { |
+ fn = new JS.Fun( |
+ params, js.statement('{ return this.#(#); }', [name, params])); |
+ } |
+ } else { |
+ fn = _emitFunctionBody(params, node.body); |
+ } |
+ |
if (node.operatorKeyword != null && |
node.name.name == '[]=' && |
params.isNotEmpty) { |
@@ -3555,27 +3589,18 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator { |
} |
} |
-class JSGenerator extends CodeGenerator { |
- final _extensionTypes = new HashSet<ClassElement>(); |
+class _ExtensionFinder extends GeneralizingElementVisitor { |
+ final AnalysisContext _context; |
+ final HashSet<ClassElement> _extensionTypes; |
final TypeProvider _types; |
- JSGenerator(AbstractCompiler compiler) |
- : _types = compiler.context.typeProvider, |
- super(compiler) { |
- // TODO(jacobr): determine the the set of types with extension methods from |
- // the annotations rather than hard coding the list once the analyzer |
- // supports summaries. |
- var context = compiler.context; |
- var src = context.sourceFactory.forUri('dart:_interceptors'); |
- var interceptors = context.computeLibraryElement(src); |
- for (var t in ['JSArray', 'JSString', 'JSNumber', 'JSBool']) { |
- _addExtensionType(interceptors.getType(t).type); |
+ |
+ _ExtensionFinder(this._context, this._extensionTypes, this._types); |
+ |
+ visitClassElement(ClassElement element) { |
+ if (findAnnotation(element, isJsPeerInterface) != null || |
+ findAnnotation(element, isNativeAnnotation) != null) { |
+ _addExtensionType(element.type); |
} |
- // TODO(jmesserly): manually add `int` and `double` |
- // Unfortunately our current analyzer rejects "implements int". |
- // Fix was landed, so we can remove this hack once we're updated: |
- // https://github.com/dart-lang/sdk/commit/d7cd11f86a02f55269fc8d9843e7758ebeeb81c8 |
- _addExtensionType(_types.intType); |
- _addExtensionType(_types.doubleType); |
} |
void _addExtensionType(InterfaceType t) { |
@@ -3586,6 +3611,35 @@ class JSGenerator extends CodeGenerator { |
_addExtensionType(t.superclass); |
} |
+ void _addExtensionTypes(String libraryUri) { |
+ var sourceFactory = _context.sourceFactory.forUri(libraryUri); |
+ var library = _context.computeLibraryElement(sourceFactory); |
+ visitLibraryElement(library); |
+ } |
+} |
+ |
+class JSGenerator extends CodeGenerator { |
+ final _extensionTypes = new HashSet<ClassElement>(); |
+ final TypeProvider _types; |
+ |
+ JSGenerator(AbstractCompiler compiler) |
+ : _types = compiler.context.typeProvider, |
+ super(compiler) { |
+ // TODO(vsm): Eventually, we want to make this extensible - i.e., find |
+ // annotations in user code as well. It would need to be summarized in |
+ // the element model - not searched this way on every compile. |
+ var finder = new _ExtensionFinder(context, _extensionTypes, _types); |
+ finder._addExtensionTypes('dart:_interceptors'); |
+ finder._addExtensionTypes('dart:_native_typed_data'); |
+ |
+ // TODO(vsm): If we're analyzing against the main SDK, those |
+ // types are not explicitly annotated. |
+ finder._addExtensionType(_types.intType); |
+ finder._addExtensionType(_types.doubleType); |
+ finder._addExtensionType(_types.boolType); |
+ finder._addExtensionType(_types.stringType); |
+ } |
+ |
String generateLibrary(LibraryUnit unit) { |
// Clone the AST first, so we can mutate it. |
unit = unit.clone(); |