Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: pkg/compiler/lib/src/js_backend/native_data.dart

Issue 2731163002: Split js interop registration into library/class/member elements (Closed)
Patch Set: Cleanup. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 library js_backend.native_data; 5 library js_backend.native_data;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../elements/elements.dart' 8 import '../elements/elements.dart'
9 show 9 show
10 ClassElement, 10 ClassElement,
11 Element, 11 Element,
12 FieldElement, 12 FieldElement,
13 FunctionElement,
14 LibraryElement, 13 LibraryElement,
15 MemberElement, 14 MemberElement,
16 MethodElement; 15 MethodElement;
17 import '../elements/entities.dart'; 16 import '../elements/entities.dart';
18 import '../native/behavior.dart' show NativeBehavior; 17 import '../native/behavior.dart' show NativeBehavior;
19 18
20 /// Basic information for native classes and methods and js-interop 19 /// Basic information for native classes and methods and js-interop
21 /// classes. 20 /// classes.
22 /// 21 ///
23 /// This information is computed during loading using [NativeClassDataBuilder]. 22 /// This information is computed during loading using [NativeClassDataBuilder].
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 NativeBehavior getNativeMethodBehavior(MethodElement method); 55 NativeBehavior getNativeMethodBehavior(MethodElement method);
57 56
58 /// Returns the [NativeBehavior] for reading from the native [field]. 57 /// Returns the [NativeBehavior] for reading from the native [field].
59 NativeBehavior getNativeFieldLoadBehavior(FieldElement field); 58 NativeBehavior getNativeFieldLoadBehavior(FieldElement field);
60 59
61 /// Returns the [NativeBehavior] for writing to the native [field]. 60 /// Returns the [NativeBehavior] for writing to the native [field].
62 NativeBehavior getNativeFieldStoreBehavior(FieldElement field); 61 NativeBehavior getNativeFieldStoreBehavior(FieldElement field);
63 62
64 /// Returns `true` if the name of [element] is fixed for the generated 63 /// Returns `true` if the name of [element] is fixed for the generated
65 /// JavaScript. 64 /// JavaScript.
66 bool hasFixedBackendName(Element element); 65 bool hasFixedBackendName(MemberElement element);
67 66
68 /// Computes the name for [element] to use in the generated JavaScript. This 67 /// Computes the name for [element] to use in the generated JavaScript. This
69 /// is either given through a native annotation or a js interop annotation. 68 /// is either given through a native annotation or a js interop annotation.
70 String getFixedBackendName(Entity entity); 69 String getFixedBackendName(MemberEntity element);
70
71 /// Computes the name prefix for [element to use in the generated JavaScript.
Siggi Cherem (dart-lang) 2017/03/14 04:48:19 nit: add missing ]
Johnni Winther 2017/03/15 11:42:14 Done.
72 /// For static and top-level members and constructors this is based on the
73 /// names for the library and/or the enclosing class.
Siggi Cherem (dart-lang) 2017/03/14 04:48:19 might be worth clarifying that here you mean JS na
Johnni Winther 2017/03/15 11:42:14 Done.
74 String getFixedBackendMethodPath(MethodElement element);
71 75
72 /// Returns the list of non-directive native tag words for [cls]. 76 /// Returns the list of non-directive native tag words for [cls].
73 List<String> getNativeTagsOfClass(ClassElement cls); 77 List<String> getNativeTagsOfClass(ClassElement cls);
74 78
75 /// Returns `true` if [cls] has a `!nonleaf` tag word. 79 /// Returns `true` if [cls] has a `!nonleaf` tag word.
76 bool hasNativeTagsForcedNonLeaf(ClassElement cls); 80 bool hasNativeTagsForcedNonLeaf(ClassElement cls);
77 81
78 /// Returns `true` if [element] is part of JsInterop. 82 /// Returns `true` if [element] is a JsInterop method.
79 /// 83 bool isJsInteropMember(MemberEntity element);
80 /// Deprecated: Use [isJsInteropLibrary], [isJsInteropClass] or
81 /// [isJsInteropMember] instead.
82 @deprecated
83 bool isJsInterop(Element element);
84 84
85 /// Returns `true` if [element] is a JsInterop method. 85 /// Returns the explicit js interop name for library [element].
86 bool isJsInteropMember(MethodElement element); 86 String getJsInteropLibraryName(LibraryElement element);
87 87
88 /// Returns the explicit js interop name for [element]. 88 /// Returns the explicit js interop name for class [element].
89 String getJsInteropName(Element element); 89 String getJsInteropClassName(ClassElement element);
90
91 /// Returns the explicit js interop name for member [element].
92 String getJsInteropMemberName(MemberElement element);
90 93
91 /// Apply JS$ escaping scheme to convert possible escaped Dart names into 94 /// Apply JS$ escaping scheme to convert possible escaped Dart names into
92 /// JS names. 95 /// JS names.
93 String getUnescapedJSInteropName(String name); 96 String computeUnescapedJSInteropName(String name);
94 } 97 }
95 98
96 abstract class NativeClassDataBuilder { 99 abstract class NativeClassDataBuilder {
97 /// Sets the native tag info for [cls]. 100 /// Sets the native tag info for [cls].
98 /// 101 ///
99 /// The tag info string contains comma-separated 'words' which are either 102 /// The tag info string contains comma-separated 'words' which are either
100 /// dispatch tags (having JavaScript identifier syntax) and directives that 103 /// dispatch tags (having JavaScript identifier syntax) and directives that
101 /// begin with `!`. 104 /// begin with `!`.
102 void setNativeClassTagInfo(ClassElement cls, String tagInfo); 105 void setNativeClassTagInfo(ClassElement cls, String tagInfo);
103 106
(...skipping 20 matching lines...) Expand all
124 List<String> getNativeTagsOfClassRaw(ClassElement cls); 127 List<String> getNativeTagsOfClassRaw(ClassElement cls);
125 128
126 /// Returns [element] as an explicit part of JsInterop. The js interop name is 129 /// Returns [element] as an explicit part of JsInterop. The js interop name is
127 /// expected to be computed later. 130 /// expected to be computed later.
128 void markAsJsInteropMember(MemberElement element); 131 void markAsJsInteropMember(MemberElement element);
129 132
130 /// Sets the native [name] for the member [element]. This name is used for 133 /// Sets the native [name] for the member [element]. This name is used for
131 /// [element] in the generated JavaScript. 134 /// [element] in the generated JavaScript.
132 void setNativeMemberName(MemberElement element, String name); 135 void setNativeMemberName(MemberElement element, String name);
133 136
134 /// Sets the explicit js interop [name] for [element]. 137 /// Sets the explicit js interop [name] for the library [element].
135 void setJsInteropName(Element element, String name); 138 void setJsInteropLibraryName(LibraryElement element, String name);
139
140 /// Sets the explicit js interop [name] for the class [element].
141 void setJsInteropClassName(ClassElement element, String name);
142
143 /// Sets the explicit js interop [name] for the member [element].
144 void setJsInteropMemberName(MemberElement element, String name);
136 } 145 }
137 146
138 class NativeDataImpl 147 class NativeDataImpl
139 implements NativeData, NativeDataBuilder, NativeClassDataBuilder { 148 implements NativeData, NativeDataBuilder, NativeClassDataBuilder {
140 /// The JavaScript names for elements implemented via typed JavaScript 149 /// The JavaScript names for elements implemented via typed JavaScript
141 /// interop. 150 /// interop.
142 Map<Element, String> jsInteropNames = <Element, String>{}; 151 Map<LibraryElement, String> jsInteropLibraryNames =
152 <LibraryElement, String>{};
153 Map<ClassElement, String> jsInteropClassNames = <ClassElement, String>{};
154 Map<MemberElement, String> jsInteropMemberNames = <MemberElement, String>{};
143 155
144 /// The JavaScript names for native JavaScript elements implemented. 156 /// The JavaScript names for native JavaScript elements implemented.
145 Map<Element, String> nativeMemberName = <Element, String>{}; 157 Map<Element, String> nativeMemberName = <Element, String>{};
146 158
147 /// Tag info for native JavaScript classes names. See 159 /// Tag info for native JavaScript classes names. See
148 /// [setNativeClassTagInfo]. 160 /// [setNativeClassTagInfo].
149 Map<ClassElement, String> nativeClassTagInfo = <ClassElement, String>{}; 161 Map<ClassElement, String> nativeClassTagInfo = <ClassElement, String>{};
150 162
151 /// Cache for [NativeBehavior]s for calling native methods. 163 /// Cache for [NativeBehavior]s for calling native methods.
152 Map<MethodElement, NativeBehavior> nativeMethodBehavior = 164 Map<MethodElement, NativeBehavior> nativeMethodBehavior =
153 <MethodElement, NativeBehavior>{}; 165 <MethodElement, NativeBehavior>{};
154 166
155 /// Cache for [NativeBehavior]s for reading from native fields. 167 /// Cache for [NativeBehavior]s for reading from native fields.
156 Map<MemberElement, NativeBehavior> nativeFieldLoadBehavior = 168 Map<MemberElement, NativeBehavior> nativeFieldLoadBehavior =
157 <FieldElement, NativeBehavior>{}; 169 <FieldElement, NativeBehavior>{};
158 170
159 /// Cache for [NativeBehavior]s for writing to native fields. 171 /// Cache for [NativeBehavior]s for writing to native fields.
160 Map<MemberElement, NativeBehavior> nativeFieldStoreBehavior = 172 Map<MemberElement, NativeBehavior> nativeFieldStoreBehavior =
161 <FieldElement, NativeBehavior>{}; 173 <FieldElement, NativeBehavior>{};
162 174
163 /// Prefix used to escape JS names that are not valid Dart names 175 /// Prefix used to escape JS names that are not valid Dart names
164 /// when using JSInterop. 176 /// when using JSInterop.
165 static const String _jsInteropEscapePrefix = r'JS$'; 177 static const String _jsInteropEscapePrefix = r'JS$';
166 178
167 /// Returns `true` if [element] is explicitly marked as part of JsInterop. 179 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
168 bool _isJsInterop(Element element) { 180 bool _isJsInteropLibrary(LibraryElement element) {
169 return jsInteropNames.containsKey(element.declaration); 181 return jsInteropLibraryNames.containsKey(element);
170 } 182 }
171 183
172 /// Marks [element] as an explicit part of JsInterop. The js interop name is 184 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
173 /// expected to be computed later. 185 bool _isJsInteropClass(ClassElement element) {
174 void markAsJsInterop(Element element) { 186 return jsInteropClassNames.containsKey(element);
175 jsInteropNames[element.declaration] = null; 187 }
188
189 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
190 bool _isJsInteropMember(MemberElement element) {
191 return jsInteropMemberNames.containsKey(element);
176 } 192 }
177 193
178 @override 194 @override
179 void markAsJsInteropLibrary(LibraryElement element) { 195 void markAsJsInteropLibrary(LibraryElement element) {
180 markAsJsInterop(element); 196 jsInteropLibraryNames[element] = null;
181 } 197 }
182 198
183 @override 199 @override
184 void markAsJsInteropClass(ClassElement element) { 200 void markAsJsInteropClass(ClassElement element) {
185 markAsJsInterop(element); 201 jsInteropClassNames[element] = null;
186 } 202 }
187 203
188 @override 204 @override
189 void markAsJsInteropMember(MemberElement element) { 205 void markAsJsInteropMember(MemberElement element) {
190 markAsJsInterop(element); 206 jsInteropMemberNames[element] = null;
191 } 207 }
192 208
193 /// Sets the explicit js interop [name] for [element]. 209 /// Sets the explicit js interop [name] for the library [element].
194 void setJsInteropName(Element element, String name) { 210 void setJsInteropLibraryName(LibraryElement element, String name) {
195 assert(invariant(element, isJsInterop(element), 211 assert(invariant(element, _isJsInteropLibrary(element),
196 message: 212 message:
197 'Element $element is not js interop but given a js interop name.')); 213 'Library $element is not js interop but given a js interop name.'));
198 jsInteropNames[element.declaration] = name; 214 jsInteropLibraryNames[element] = name;
199 } 215 }
200 216
201 /// Returns the explicit js interop name for [element]. 217 /// Sets the explicit js interop [name] for the class [element].
202 String getJsInteropName(Element element) { 218 void setJsInteropClassName(ClassElement element, String name) {
203 return jsInteropNames[element.declaration]; 219 assert(invariant(element, _isJsInteropClass(element),
220 message:
221 'Class $element is not js interop but given a js interop name.'));
222 jsInteropClassNames[element] = name;
204 } 223 }
205 224
206 /// Returns `true` if [element] is part of JsInterop. 225 /// Sets the explicit js interop [name] for the member [element].
207 bool isJsInterop(Element element) { 226 void setJsInteropMemberName(MemberElement element, String name) {
208 // An function is part of JsInterop in the following cases: 227 assert(invariant(element, _isJsInteropMember(element),
209 // * It has a jsInteropName annotation 228 message:
210 // * It is external member of a class or library tagged as JsInterop. 229 'Member $element is not js interop but given a js interop name.'));
230 jsInteropMemberNames[element] = name;
231 }
232
233 /// Returns the explicit js interop name for library [element].
234 String getJsInteropLibraryName(LibraryElement element) {
235 return jsInteropLibraryNames[element];
236 }
237
238 /// Returns the explicit js interop name for class [element].
239 String getJsInteropClassName(ClassElement element) {
240 return jsInteropClassNames[element];
241 }
242
243 /// Returns the explicit js interop name for member [element].
244 String getJsInteropMemberName(MemberElement element) {
245 return jsInteropMemberNames[element];
246 }
247
248 /// Returns `true` if [element] is a JsInterop library.
249 bool isJsInteropLibrary(LibraryElement element) =>
250 _isJsInteropLibrary(element);
251
252 /// Returns `true` if [element] is a JsInterop class.
253 bool isJsInteropClass(ClassElement element) => _isJsInteropClass(element);
254
255 /// Returns `true` if [element] is a JsInterop method.
256 bool isJsInteropMember(MemberElement element) {
211 if (element.isFunction || element.isConstructor || element.isAccessor) { 257 if (element.isFunction || element.isConstructor || element.isAccessor) {
212 FunctionElement function = element; 258 MethodElement function = element;
213 if (!function.isExternal) return false; 259 if (!function.isExternal) return false;
214 260
215 if (_isJsInterop(function)) return true; 261 if (_isJsInteropMember(function)) return true;
216 if (function.isClassMember) return isJsInterop(function.contextClass); 262 if (function.isClassMember) {
217 if (function.isTopLevel) return isJsInterop(function.library); 263 return _isJsInteropClass(function.enclosingClass);
264 }
265 if (function.isTopLevel) {
266 return _isJsInteropLibrary(function.library);
267 }
218 return false; 268 return false;
219 } else { 269 } else {
220 return _isJsInterop(element); 270 return _isJsInteropMember(element);
221 } 271 }
222 } 272 }
223 273
224 /// Returns `true` if [element] is a JsInterop library.
225 bool isJsInteropLibrary(LibraryElement element) => isJsInterop(element);
226
227 /// Returns `true` if [element] is a JsInterop class.
228 bool isJsInteropClass(ClassElement element) => isJsInterop(element);
229
230 /// Returns `true` if [element] is a JsInterop method.
231 bool isJsInteropMember(MethodElement element) => isJsInterop(element);
232
233 /// Returns `true` if the name of [element] is fixed for the generated 274 /// Returns `true` if the name of [element] is fixed for the generated
234 /// JavaScript. 275 /// JavaScript.
235 bool hasFixedBackendName(Element element) { 276 bool hasFixedBackendName(MemberElement element) {
236 return isJsInterop(element) || 277 return isJsInteropMember(element) ||
237 nativeMemberName.containsKey(element.declaration); 278 nativeMemberName.containsKey(element.declaration);
238 } 279 }
239 280
240 String _jsNameHelper(Element element) {
241 String jsInteropName = jsInteropNames[element.declaration];
242 assert(invariant(element, !(_isJsInterop(element) && jsInteropName == null),
243 message:
244 'Element $element is js interop but js interop name has not yet '
245 'been computed.'));
246 if (jsInteropName != null && jsInteropName.isNotEmpty) {
247 return jsInteropName;
248 }
249 return element.isLibrary ? 'self' : getUnescapedJSInteropName(element.name);
250 }
251
252 /// Computes the name for [element] to use in the generated JavaScript. This 281 /// Computes the name for [element] to use in the generated JavaScript. This
253 /// is either given through a native annotation or a js interop annotation. 282 /// is either given through a native annotation or a js interop annotation.
254 String getFixedBackendName(Entity entity) { 283 String getFixedBackendName(MemberElement element) {
255 // TODO(johnniwinther): Remove this assignment from [Entity] to [Element]
256 // when `.declaration` is no longer needed.
257 Element element = entity;
258 String name = nativeMemberName[element.declaration]; 284 String name = nativeMemberName[element.declaration];
259 if (name == null && isJsInterop(element)) { 285 if (name == null && isJsInteropMember(element)) {
260 // If an element isJsInterop but _isJsInterop is false that means it is 286 // If an element isJsInterop but _isJsInterop is false that means it is
261 // considered interop as the parent class is interop. 287 // considered interop as the parent class is interop.
262 name = _jsNameHelper( 288 name = element.isConstructor
263 element.isConstructor ? element.enclosingClass : element); 289 ? _jsClassNameHelper(element.enclosingClass)
290 : _jsMemberNameHelper(element);
264 nativeMemberName[element.declaration] = name; 291 nativeMemberName[element.declaration] = name;
265 } 292 }
266 return name; 293 return name;
267 } 294 }
268 295
269 /// Whether [element] corresponds to a native JavaScript construct either 296 String _jsLibraryNameHelper(LibraryElement element) {
270 /// through the native mechanism (`@Native(...)` or the `native` pseudo 297 String jsInteropName = getJsInteropLibraryName(element);
271 /// keyword) which is only allowed for internal libraries or via the typed 298 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
272 /// JavaScriptInterop mechanism which is allowed for user libraries. 299 return 'self';
273 bool isNative(Element element) { 300 }
274 if (isJsInterop(element)) return true; 301
275 if (element.isClass) { 302 String _jsClassNameHelper(ClassElement element) {
276 return nativeClassTagInfo.containsKey(element.declaration); 303 String jsInteropName = getJsInteropClassName(element);
277 } else { 304 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
278 return nativeMemberName.containsKey(element.declaration); 305 return computeUnescapedJSInteropName(element.name);
306 }
307
308 String _jsMemberNameHelper(MemberElement element) {
309 String jsInteropName = jsInteropMemberNames[element];
310 assert(invariant(element,
311 !(jsInteropMemberNames.containsKey(element) && jsInteropName == null),
312 message:
313 'Member $element is js interop but js interop name has not yet '
314 'been computed.'));
315 if (jsInteropName != null && jsInteropName.isNotEmpty) {
316 return jsInteropName;
279 } 317 }
318 return computeUnescapedJSInteropName(element.name);
319 }
320
321 /// Returns a JavaScript path specifying the context in which
322 /// [element.fixedBackendName] should be evaluated. Only applicable for
323 /// elements using typed JavaScript interop.
324 /// For example: fixedBackendPath for the static method createMap in the
325 /// Map class of the goog.map JavaScript library would have path
326 /// "goog.maps.Map".
327 String getFixedBackendMethodPath(MethodElement element) {
328 if (!isJsInteropMember(element)) return null;
329 if (element.isInstanceMember) return 'this';
330 if (element.isConstructor) {
331 return _fixedBackendClassPath(element.enclosingClass);
332 }
333 StringBuffer sb = new StringBuffer();
334 sb.write(_jsLibraryNameHelper(element.library));
335 if (element.enclosingClass != null) {
336 sb..write('.')..write(_jsClassNameHelper(element.enclosingClass));
337 }
338 return sb.toString();
339 }
340
341 String _fixedBackendClassPath(ClassElement element) {
342 if (!isJsInteropClass(element)) return null;
343 return _jsLibraryNameHelper(element.library);
280 } 344 }
281 345
282 /// Returns `true` if [cls] is a native class. 346 /// Returns `true` if [cls] is a native class.
283 bool isNativeClass(ClassElement element) => isNative(element); 347 bool isNativeClass(ClassElement element) {
348 if (isJsInteropClass(element)) return true;
349 return nativeClassTagInfo.containsKey(element);
350 }
284 351
285 /// Returns `true` if [element] is a native member of a native class. 352 /// Returns `true` if [element] is a native member of a native class.
286 bool isNativeMember(MemberElement element) => isNative(element); 353 bool isNativeMember(MemberElement element) {
354 if (isJsInteropMember(element)) return true;
355 return nativeMemberName.containsKey(element);
356 }
287 357
288 /// Returns `true` if [element] or any of its superclasses is native. 358 /// Returns `true` if [element] or any of its superclasses is native.
289 bool isNativeOrExtendsNative(ClassElement element) { 359 bool isNativeOrExtendsNative(ClassElement element) {
290 if (element == null) return false; 360 if (element == null) return false;
291 if (isNativeClass(element) || isJsInteropClass(element)) { 361 if (isNativeClass(element) || isJsInteropClass(element)) {
292 return true; 362 return true;
293 } 363 }
294 assert(element.isResolved); 364 assert(element.isResolved);
295 return isNativeOrExtendsNative(element.superclass); 365 return isNativeOrExtendsNative(element.superclass);
296 } 366 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 } 453 }
384 454
385 /// Registers the [behavior] for writing to the native [field]. 455 /// Registers the [behavior] for writing to the native [field].
386 void setNativeFieldStoreBehavior( 456 void setNativeFieldStoreBehavior(
387 FieldElement field, NativeBehavior behavior) { 457 FieldElement field, NativeBehavior behavior) {
388 nativeFieldStoreBehavior[field] = behavior; 458 nativeFieldStoreBehavior[field] = behavior;
389 } 459 }
390 460
391 /// Apply JS$ escaping scheme to convert possible escaped Dart names into 461 /// Apply JS$ escaping scheme to convert possible escaped Dart names into
392 /// JS names. 462 /// JS names.
393 String getUnescapedJSInteropName(String name) { 463 String computeUnescapedJSInteropName(String name) {
394 return name.startsWith(_jsInteropEscapePrefix) 464 return name.startsWith(_jsInteropEscapePrefix)
395 ? name.substring(_jsInteropEscapePrefix.length) 465 ? name.substring(_jsInteropEscapePrefix.length)
396 : name; 466 : name;
397 } 467 }
398 } 468 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698