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 /// Analysis to determine how to generate code for typed JavaScript interop. | 5 /// Analysis to determine how to generate code for typed JavaScript interop. |
6 library compiler.src.js_backend.js_interop_analysis; | 6 library compiler.src.js_backend.js_interop_analysis; |
7 | 7 |
8 import '../common/names.dart' show Identifiers; | 8 import '../common/names.dart' show Identifiers; |
9 import '../compiler.dart' show Compiler; | 9 import '../compiler.dart' show Compiler; |
10 import '../diagnostics/messages.dart' show MessageKind; | 10 import '../diagnostics/messages.dart' show MessageKind; |
11 import '../constants/values.dart' | 11 import '../constants/values.dart' |
12 show | 12 show |
13 ConstantValue, | 13 ConstantValue, |
14 ConstructedConstantValue, | 14 ConstructedConstantValue, |
15 ListConstantValue, | 15 ListConstantValue, |
16 NullConstantValue, | 16 NullConstantValue, |
17 StringConstantValue, | 17 StringConstantValue, |
18 TypeConstantValue; | 18 TypeConstantValue; |
19 import '../elements/elements.dart' | 19 import '../elements/elements.dart' |
20 show | 20 show |
21 ClassElement, | 21 ClassElement, |
22 Element, | 22 Element, |
23 FieldElement, | 23 FieldElement, |
24 FunctionElement, | 24 FunctionElement, |
25 LibraryElement, | 25 LibraryElement, |
| 26 ParameterElement, |
26 MetadataAnnotation; | 27 MetadataAnnotation; |
27 | 28 |
28 import '../js/js.dart' as jsAst; | 29 import '../js/js.dart' as jsAst; |
29 import '../js/js.dart' show js; | 30 import '../js/js.dart' show js; |
30 import '../universe/selector.dart' show Selector; | 31 import '../universe/selector.dart' show Selector; |
31 import '../universe/universe.dart' show SelectorConstraints; | 32 import '../universe/universe.dart' show SelectorConstraints; |
32 | 33 |
33 import 'backend_helpers.dart' show BackendHelpers; | 34 import 'backend_helpers.dart' show BackendHelpers; |
34 import 'js_backend.dart' show JavaScriptBackend; | 35 import 'js_backend.dart' show JavaScriptBackend; |
35 | 36 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 } else { | 77 } else { |
77 // TODO(jacobr): report a warning if the value is not a String. | 78 // TODO(jacobr): report a warning if the value is not a String. |
78 backend.setJsInteropName(e, ''); | 79 backend.setJsInteropName(e, ''); |
79 } | 80 } |
80 enabledJsInterop = true; | 81 enabledJsInterop = true; |
81 return; | 82 return; |
82 } | 83 } |
83 } | 84 } |
84 } | 85 } |
85 | 86 |
| 87 bool hasAnonymousAnnotation(Element element) { |
| 88 if (backend.helpers.jsAnonymousClass == null) return false; |
| 89 return element.metadata.any((MetadataAnnotation annotation) { |
| 90 ConstantValue constant = backend.compiler.constants.getConstantValue( |
| 91 annotation.constant); |
| 92 if (constant == null || |
| 93 constant is! ConstructedConstantValue) return false; |
| 94 ConstructedConstantValue constructedConstant = constant; |
| 95 return constructedConstant.type.element == |
| 96 backend.helpers.jsAnonymousClass; |
| 97 }); |
| 98 } |
| 99 |
| 100 void _checkFunctionParameters(FunctionElement fn) { |
| 101 if (fn.hasFunctionSignature && |
| 102 fn.functionSignature.optionalParametersAreNamed) { |
| 103 backend.reporter.reportErrorMessage(fn, |
| 104 MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS, { |
| 105 'method': fn.name |
| 106 }); |
| 107 } |
| 108 } |
| 109 |
86 void processJsInteropAnnotationsInLibrary(LibraryElement library) { | 110 void processJsInteropAnnotationsInLibrary(LibraryElement library) { |
87 processJsInteropAnnotation(library); | 111 processJsInteropAnnotation(library); |
88 library.implementation.forEachLocalMember((Element element) { | 112 library.implementation.forEachLocalMember((Element element) { |
89 processJsInteropAnnotation(element); | 113 processJsInteropAnnotation(element); |
90 if (!element.isClass || !backend.isJsInterop(element)) return; | 114 if (!backend.isJsInterop(element)) return; |
| 115 if (element is FunctionElement) { |
| 116 _checkFunctionParameters(element); |
| 117 } |
| 118 |
| 119 if (!element.isClass) return; |
91 | 120 |
92 ClassElement classElement = element; | 121 ClassElement classElement = element; |
93 | 122 |
94 if (!classElement | 123 if (!classElement |
95 .implementsInterface(helpers.jsJavaScriptObjectClass)) { | 124 .implementsInterface(helpers.jsJavaScriptObjectClass)) { |
96 backend.reporter.reportErrorMessage(classElement, | 125 backend.reporter.reportErrorMessage(classElement, |
97 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, { | 126 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, { |
98 'cls': classElement.name, | 127 'cls': classElement.name, |
99 'superclass': classElement.superclass.name | 128 'superclass': classElement.superclass.name |
100 }); | 129 }); |
101 } | 130 } |
102 | 131 |
103 classElement.forEachMember( | 132 classElement.forEachMember( |
104 (ClassElement classElement, Element member) { | 133 (ClassElement classElement, Element member) { |
105 processJsInteropAnnotation(member); | 134 processJsInteropAnnotation(member); |
106 | 135 |
107 if (!member.isSynthesized && | 136 if (!member.isSynthesized && |
108 backend.isJsInterop(classElement) && | 137 backend.isJsInterop(classElement) && |
109 member is FunctionElement) { | 138 member is FunctionElement) { |
110 FunctionElement fn = member; | 139 FunctionElement fn = member; |
111 if (!fn.isExternal && !fn.isAbstract) { | 140 if (!fn.isExternal && !fn.isAbstract && !fn.isConstructor && |
| 141 !fn.isStatic) { |
112 backend.reporter.reportErrorMessage( | 142 backend.reporter.reportErrorMessage( |
113 fn, | 143 fn, |
114 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER, | 144 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER, |
115 {'cls': classElement.name, 'member': member.name}); | 145 {'cls': classElement.name, 'member': member.name}); |
116 } | 146 } |
| 147 |
| 148 if (fn.isFactoryConstructor && hasAnonymousAnnotation(classElement)) { |
| 149 fn.functionSignature.orderedForEachParameter( |
| 150 (ParameterElement parameter) { |
| 151 if (!parameter.isNamed) { |
| 152 backend.reporter.reportErrorMessage(parameter, |
| 153 MessageKind |
| 154 .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS
, |
| 155 { |
| 156 'parameter': parameter.name, |
| 157 'cls': classElement.name |
| 158 }); |
| 159 } |
| 160 }); |
| 161 } else { |
| 162 _checkFunctionParameters(fn); |
| 163 } |
117 } | 164 } |
118 }); | 165 }); |
119 }); | 166 }); |
120 } | 167 } |
121 | 168 |
122 jsAst.Statement buildJsInteropBootstrap() { | 169 jsAst.Statement buildJsInteropBootstrap() { |
123 if (!enabledJsInterop) return null; | 170 if (!enabledJsInterop) return null; |
124 List<jsAst.Statement> statements = <jsAst.Statement>[]; | 171 List<jsAst.Statement> statements = <jsAst.Statement>[]; |
125 backend.compiler.codegenWorld.forEachInvokedName( | 172 backend.compiler.codegenWorld.forEachInvokedName( |
126 (String name, Map<Selector, SelectorConstraints> selectors) { | 173 (String name, Map<Selector, SelectorConstraints> selectors) { |
(...skipping 10 matching lines...) Expand all Loading... |
137 var name = backend.namer.invocationName(selector); | 184 var name = backend.namer.invocationName(selector); |
138 statements.add(js.statement( | 185 statements.add(js.statement( |
139 'Function.prototype.# = function(#) { return this(#) }', | 186 'Function.prototype.# = function(#) { return this(#) }', |
140 [name, parameters, parameters])); | 187 [name, parameters, parameters])); |
141 } | 188 } |
142 }); | 189 }); |
143 }); | 190 }); |
144 return new jsAst.Block(statements); | 191 return new jsAst.Block(statements); |
145 } | 192 } |
146 } | 193 } |
OLD | NEW |