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

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

Issue 2731173002: Add ClassEntity.library, MemberEntity.library and FunctionEntity.isExternal (Closed)
Patch Set: 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' show ClassElement;
9 show
10 ClassElement,
11 Element,
12 FieldElement,
13 LibraryElement,
14 MemberElement,
15 MethodElement;
16 import '../elements/entities.dart'; 9 import '../elements/entities.dart';
17 import '../native/behavior.dart' show NativeBehavior; 10 import '../native/behavior.dart' show NativeBehavior;
18 11
19 /// Basic information for native classes and methods and js-interop 12 /// Basic information for native classes and methods and js-interop
20 /// classes. 13 /// classes.
21 /// 14 ///
22 /// This information is computed during loading using [NativeClassDataBuilder]. 15 /// This information is computed during loading using [NativeClassDataBuilder].
23 abstract class NativeClassData { 16 abstract class NativeClassData {
24 /// Returns `true` if [cls] corresponds to a native JavaScript class. 17 /// Returns `true` if [cls] corresponds to a native JavaScript class.
25 /// 18 ///
26 /// A class is marked as native either through the `@Native(...)` annotation 19 /// A class is marked as native either through the `@Native(...)` annotation
27 /// allowed for internal libraries or via the typed JavaScriptInterop 20 /// allowed for internal libraries or via the typed JavaScriptInterop
28 /// mechanism allowed for user libraries. 21 /// mechanism allowed for user libraries.
29 bool isNativeClass(ClassEntity element); 22 bool isNativeClass(ClassEntity element);
30 23
31 /// Returns `true` if [element] or any of its superclasses is native. 24 /// Returns `true` if [element] or any of its superclasses is native.
32 bool isNativeOrExtendsNative(ClassElement element); 25 bool isNativeOrExtendsNative(ClassEntity element);
33 26
34 /// Returns `true` if [element] is a JsInterop library. 27 /// Returns `true` if [element] is a JsInterop library.
35 bool isJsInteropLibrary(LibraryElement element); 28 bool isJsInteropLibrary(LibraryEntity element);
36 29
37 /// Returns `true` if [element] is a JsInterop class. 30 /// Returns `true` if [element] is a JsInterop class.
38 bool isJsInteropClass(ClassElement element); 31 bool isJsInteropClass(ClassEntity element);
39 } 32 }
40 33
41 /// Additional element information for native classes and methods and js-interop 34 /// Additional element information for native classes and methods and js-interop
42 /// methods. 35 /// methods.
43 /// 36 ///
44 /// This information is computed during resolution using [NativeDataBuilder]. 37 /// This information is computed during resolution using [NativeDataBuilder].
45 abstract class NativeData extends NativeClassData { 38 abstract class NativeData extends NativeClassData {
46 /// Returns `true` if [element] corresponds to a native JavaScript member. 39 /// Returns `true` if [element] corresponds to a native JavaScript member.
47 /// 40 ///
48 /// A member is marked as native either through the native mechanism 41 /// A member is marked as native either through the native mechanism
49 /// (`@Native(...)` or the `native` pseudo keyword) allowed for internal 42 /// (`@Native(...)` or the `native` pseudo keyword) allowed for internal
50 /// libraries or via the typed JavaScriptInterop mechanism allowed for user 43 /// libraries or via the typed JavaScriptInterop mechanism allowed for user
51 /// libraries. 44 /// libraries.
52 bool isNativeMember(MemberEntity element); 45 bool isNativeMember(MemberEntity element);
53 46
54 /// Returns the [NativeBehavior] for calling the native [method]. 47 /// Returns the [NativeBehavior] for calling the native [method].
55 NativeBehavior getNativeMethodBehavior(MethodElement method); 48 NativeBehavior getNativeMethodBehavior(FunctionEntity method);
56 49
57 /// Returns the [NativeBehavior] for reading from the native [field]. 50 /// Returns the [NativeBehavior] for reading from the native [field].
58 NativeBehavior getNativeFieldLoadBehavior(FieldElement field); 51 NativeBehavior getNativeFieldLoadBehavior(FieldEntity field);
59 52
60 /// Returns the [NativeBehavior] for writing to the native [field]. 53 /// Returns the [NativeBehavior] for writing to the native [field].
61 NativeBehavior getNativeFieldStoreBehavior(FieldElement field); 54 NativeBehavior getNativeFieldStoreBehavior(FieldEntity field);
62 55
63 /// Returns `true` if the name of [element] is fixed for the generated 56 /// Returns `true` if the name of [element] is fixed for the generated
64 /// JavaScript. 57 /// JavaScript.
65 bool hasFixedBackendName(MemberElement element); 58 bool hasFixedBackendName(MemberEntity element);
66 59
67 /// Computes the name for [element] to use in the generated JavaScript. This 60 /// Computes the name for [element] to use in the generated JavaScript. This
68 /// is either given through a native annotation or a js interop annotation. 61 /// is either given through a native annotation or a js interop annotation.
69 String getFixedBackendName(MemberEntity element); 62 String getFixedBackendName(MemberEntity element);
70 63
71 /// Computes the name prefix for [element to use in the generated JavaScript. 64 /// Computes the name prefix for [element to use in the generated JavaScript.
72 /// For static and top-level members and constructors this is based on the 65 /// For static and top-level members and constructors this is based on the
73 /// names for the library and/or the enclosing class. 66 /// names for the library and/or the enclosing class.
74 String getFixedBackendMethodPath(MethodElement element); 67 String getFixedBackendMethodPath(FunctionEntity element);
75 68
76 /// Returns the list of non-directive native tag words for [cls]. 69 /// Returns the list of non-directive native tag words for [cls].
77 List<String> getNativeTagsOfClass(ClassElement cls); 70 List<String> getNativeTagsOfClass(ClassEntity cls);
78 71
79 /// Returns `true` if [cls] has a `!nonleaf` tag word. 72 /// Returns `true` if [cls] has a `!nonleaf` tag word.
80 bool hasNativeTagsForcedNonLeaf(ClassElement cls); 73 bool hasNativeTagsForcedNonLeaf(ClassEntity cls);
81 74
82 /// Returns `true` if [element] is a JsInterop method. 75 /// Returns `true` if [element] is a JsInterop method.
83 bool isJsInteropMember(MemberEntity element); 76 bool isJsInteropMember(MemberEntity element);
84 77
85 /// Returns the explicit js interop name for library [element]. 78 /// Returns the explicit js interop name for library [element].
86 String getJsInteropLibraryName(LibraryElement element); 79 String getJsInteropLibraryName(LibraryEntity element);
87 80
88 /// Returns the explicit js interop name for class [element]. 81 /// Returns the explicit js interop name for class [element].
89 String getJsInteropClassName(ClassElement element); 82 String getJsInteropClassName(ClassEntity element);
90 83
91 /// Returns the explicit js interop name for member [element]. 84 /// Returns the explicit js interop name for member [element].
92 String getJsInteropMemberName(MemberElement element); 85 String getJsInteropMemberName(MemberEntity element);
93 86
94 /// Apply JS$ escaping scheme to convert possible escaped Dart names into 87 /// Apply JS$ escaping scheme to convert possible escaped Dart names into
95 /// JS names. 88 /// JS names.
96 String computeUnescapedJSInteropName(String name); 89 String computeUnescapedJSInteropName(String name);
97 } 90 }
98 91
99 abstract class NativeClassDataBuilder { 92 abstract class NativeClassDataBuilder {
100 /// Sets the native tag info for [cls]. 93 /// Sets the native tag info for [cls].
101 /// 94 ///
102 /// The tag info string contains comma-separated 'words' which are either 95 /// The tag info string contains comma-separated 'words' which are either
103 /// dispatch tags (having JavaScript identifier syntax) and directives that 96 /// dispatch tags (having JavaScript identifier syntax) and directives that
104 /// begin with `!`. 97 /// begin with `!`.
105 void setNativeClassTagInfo(ClassElement cls, String tagInfo); 98 void setNativeClassTagInfo(ClassEntity cls, String tagInfo);
106 99
107 /// Marks [element] as an explicit part of JsInterop. The js interop name is 100 /// Marks [element] as an explicit part of JsInterop. The js interop name is
108 /// expected to be computed later. 101 /// expected to be computed later.
109 void markAsJsInteropLibrary(LibraryElement element); 102 void markAsJsInteropLibrary(LibraryEntity element);
110 103
111 /// Marks [element] as an explicit part of JsInterop. The js interop name is 104 /// Marks [element] as an explicit part of JsInterop. The js interop name is
112 /// expected to be computed later. 105 /// expected to be computed later.
113 void markAsJsInteropClass(ClassElement element); 106 void markAsJsInteropClass(ClassEntity element);
114 } 107 }
115 108
116 abstract class NativeDataBuilder { 109 abstract class NativeDataBuilder {
117 /// Registers the [behavior] for calling the native [method]. 110 /// Registers the [behavior] for calling the native [method].
118 void setNativeMethodBehavior(MethodElement method, NativeBehavior behavior); 111 void setNativeMethodBehavior(FunctionEntity method, NativeBehavior behavior);
119 112
120 /// Registers the [behavior] for reading from the native [field]. 113 /// Registers the [behavior] for reading from the native [field].
121 void setNativeFieldLoadBehavior(FieldElement field, NativeBehavior behavior); 114 void setNativeFieldLoadBehavior(FieldEntity field, NativeBehavior behavior);
122 115
123 /// Registers the [behavior] for writing to the native [field]. 116 /// Registers the [behavior] for writing to the native [field].
124 void setNativeFieldStoreBehavior(FieldElement field, NativeBehavior behavior); 117 void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior);
125 118
126 /// Returns the list of native tag words for [cls]. 119 /// Returns the list of native tag words for [cls].
127 List<String> getNativeTagsOfClassRaw(ClassElement cls); 120 List<String> getNativeTagsOfClassRaw(ClassEntity cls);
128 121
129 /// Returns [element] as an explicit part of JsInterop. The js interop name is 122 /// Returns [element] as an explicit part of JsInterop. The js interop name is
130 /// expected to be computed later. 123 /// expected to be computed later.
131 void markAsJsInteropMember(MemberElement element); 124 void markAsJsInteropMember(MemberEntity element);
132 125
133 /// Sets the native [name] for the member [element]. This name is used for 126 /// Sets the native [name] for the member [element]. This name is used for
134 /// [element] in the generated JavaScript. 127 /// [element] in the generated JavaScript.
135 void setNativeMemberName(MemberElement element, String name); 128 void setNativeMemberName(MemberEntity element, String name);
136 129
137 /// Sets the explicit js interop [name] for the library [element]. 130 /// Sets the explicit js interop [name] for the library [element].
138 void setJsInteropLibraryName(LibraryElement element, String name); 131 void setJsInteropLibraryName(LibraryEntity element, String name);
139 132
140 /// Sets the explicit js interop [name] for the class [element]. 133 /// Sets the explicit js interop [name] for the class [element].
141 void setJsInteropClassName(ClassElement element, String name); 134 void setJsInteropClassName(ClassEntity element, String name);
142 135
143 /// Sets the explicit js interop [name] for the member [element]. 136 /// Sets the explicit js interop [name] for the member [element].
144 void setJsInteropMemberName(MemberElement element, String name); 137 void setJsInteropMemberName(MemberEntity element, String name);
145 } 138 }
146 139
147 class NativeDataImpl 140 class NativeDataImpl
148 implements NativeData, NativeDataBuilder, NativeClassDataBuilder { 141 implements NativeData, NativeDataBuilder, NativeClassDataBuilder {
149 /// The JavaScript names for elements implemented via typed JavaScript 142 /// The JavaScript names for elements implemented via typed JavaScript
150 /// interop. 143 /// interop.
151 Map<LibraryElement, String> jsInteropLibraryNames = 144 Map<LibraryEntity, String> jsInteropLibraryNames = <LibraryEntity, String>{};
152 <LibraryElement, String>{}; 145 Map<ClassEntity, String> jsInteropClassNames = <ClassEntity, String>{};
153 Map<ClassElement, String> jsInteropClassNames = <ClassElement, String>{}; 146 Map<MemberEntity, String> jsInteropMemberNames = <MemberEntity, String>{};
154 Map<MemberElement, String> jsInteropMemberNames = <MemberElement, String>{};
155 147
156 /// The JavaScript names for native JavaScript elements implemented. 148 /// The JavaScript names for native JavaScript elements implemented.
157 Map<Element, String> nativeMemberName = <Element, String>{}; 149 Map<MemberEntity, String> nativeMemberName = <MemberEntity, String>{};
158 150
159 /// Tag info for native JavaScript classes names. See 151 /// Tag info for native JavaScript classes names. See
160 /// [setNativeClassTagInfo]. 152 /// [setNativeClassTagInfo].
161 Map<ClassElement, String> nativeClassTagInfo = <ClassElement, String>{}; 153 Map<ClassEntity, String> nativeClassTagInfo = <ClassEntity, String>{};
162 154
163 /// Cache for [NativeBehavior]s for calling native methods. 155 /// Cache for [NativeBehavior]s for calling native methods.
164 Map<MethodElement, NativeBehavior> nativeMethodBehavior = 156 Map<FunctionEntity, NativeBehavior> nativeMethodBehavior =
165 <MethodElement, NativeBehavior>{}; 157 <FunctionEntity, NativeBehavior>{};
166 158
167 /// Cache for [NativeBehavior]s for reading from native fields. 159 /// Cache for [NativeBehavior]s for reading from native fields.
168 Map<MemberElement, NativeBehavior> nativeFieldLoadBehavior = 160 Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior =
169 <FieldElement, NativeBehavior>{}; 161 <FieldEntity, NativeBehavior>{};
170 162
171 /// Cache for [NativeBehavior]s for writing to native fields. 163 /// Cache for [NativeBehavior]s for writing to native fields.
172 Map<MemberElement, NativeBehavior> nativeFieldStoreBehavior = 164 Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior =
173 <FieldElement, NativeBehavior>{}; 165 <FieldEntity, NativeBehavior>{};
174 166
175 /// Prefix used to escape JS names that are not valid Dart names 167 /// Prefix used to escape JS names that are not valid Dart names
176 /// when using JSInterop. 168 /// when using JSInterop.
177 static const String _jsInteropEscapePrefix = r'JS$'; 169 static const String _jsInteropEscapePrefix = r'JS$';
178 170
179 /// Returns `true` if [element] is explicitly marked as part of JsInterop. 171 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
180 bool _isJsInteropLibrary(LibraryElement element) { 172 bool _isJsInteropLibrary(LibraryEntity element) {
181 return jsInteropLibraryNames.containsKey(element); 173 return jsInteropLibraryNames.containsKey(element);
182 } 174 }
183 175
184 /// Returns `true` if [element] is explicitly marked as part of JsInterop. 176 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
185 bool _isJsInteropClass(ClassElement element) { 177 bool _isJsInteropClass(ClassEntity element) {
186 return jsInteropClassNames.containsKey(element); 178 return jsInteropClassNames.containsKey(element);
187 } 179 }
188 180
189 /// Returns `true` if [element] is explicitly marked as part of JsInterop. 181 /// Returns `true` if [element] is explicitly marked as part of JsInterop.
190 bool _isJsInteropMember(MemberElement element) { 182 bool _isJsInteropMember(MemberEntity element) {
191 return jsInteropMemberNames.containsKey(element); 183 return jsInteropMemberNames.containsKey(element);
192 } 184 }
193 185
194 @override 186 @override
195 void markAsJsInteropLibrary(LibraryElement element) { 187 void markAsJsInteropLibrary(LibraryEntity element) {
196 jsInteropLibraryNames[element] = null; 188 jsInteropLibraryNames[element] = null;
197 } 189 }
198 190
199 @override 191 @override
200 void markAsJsInteropClass(ClassElement element) { 192 void markAsJsInteropClass(ClassEntity element) {
201 jsInteropClassNames[element] = null; 193 jsInteropClassNames[element] = null;
202 } 194 }
203 195
204 @override 196 @override
205 void markAsJsInteropMember(MemberElement element) { 197 void markAsJsInteropMember(MemberEntity element) {
206 jsInteropMemberNames[element] = null; 198 jsInteropMemberNames[element] = null;
207 } 199 }
208 200
209 /// Sets the explicit js interop [name] for the library [element]. 201 /// Sets the explicit js interop [name] for the library [element].
210 void setJsInteropLibraryName(LibraryElement element, String name) { 202 void setJsInteropLibraryName(LibraryEntity element, String name) {
211 assert(invariant(element, _isJsInteropLibrary(element), 203 assert(invariant(element, _isJsInteropLibrary(element),
212 message: 204 message:
213 'Library $element is not js interop but given a js interop name.')); 205 'Library $element is not js interop but given a js interop name.'));
214 jsInteropLibraryNames[element] = name; 206 jsInteropLibraryNames[element] = name;
215 } 207 }
216 208
217 /// Sets the explicit js interop [name] for the class [element]. 209 /// Sets the explicit js interop [name] for the class [element].
218 void setJsInteropClassName(ClassElement element, String name) { 210 void setJsInteropClassName(ClassEntity element, String name) {
219 assert(invariant(element, _isJsInteropClass(element), 211 assert(invariant(element, _isJsInteropClass(element),
220 message: 212 message:
221 'Class $element is not js interop but given a js interop name.')); 213 'Class $element is not js interop but given a js interop name.'));
222 jsInteropClassNames[element] = name; 214 jsInteropClassNames[element] = name;
223 } 215 }
224 216
225 /// Sets the explicit js interop [name] for the member [element]. 217 /// Sets the explicit js interop [name] for the member [element].
226 void setJsInteropMemberName(MemberElement element, String name) { 218 void setJsInteropMemberName(MemberEntity element, String name) {
227 assert(invariant(element, _isJsInteropMember(element), 219 assert(invariant(element, _isJsInteropMember(element),
228 message: 220 message:
229 'Member $element is not js interop but given a js interop name.')); 221 'Member $element is not js interop but given a js interop name.'));
230 jsInteropMemberNames[element] = name; 222 jsInteropMemberNames[element] = name;
231 } 223 }
232 224
233 /// Returns the explicit js interop name for library [element]. 225 /// Returns the explicit js interop name for library [element].
234 String getJsInteropLibraryName(LibraryElement element) { 226 String getJsInteropLibraryName(LibraryEntity element) {
235 return jsInteropLibraryNames[element]; 227 return jsInteropLibraryNames[element];
236 } 228 }
237 229
238 /// Returns the explicit js interop name for class [element]. 230 /// Returns the explicit js interop name for class [element].
239 String getJsInteropClassName(ClassElement element) { 231 String getJsInteropClassName(ClassEntity element) {
240 return jsInteropClassNames[element]; 232 return jsInteropClassNames[element];
241 } 233 }
242 234
243 /// Returns the explicit js interop name for member [element]. 235 /// Returns the explicit js interop name for member [element].
244 String getJsInteropMemberName(MemberElement element) { 236 String getJsInteropMemberName(MemberEntity element) {
245 return jsInteropMemberNames[element]; 237 return jsInteropMemberNames[element];
246 } 238 }
247 239
248 /// Returns `true` if [element] is a JsInterop library. 240 /// Returns `true` if [element] is a JsInterop library.
249 bool isJsInteropLibrary(LibraryElement element) => 241 bool isJsInteropLibrary(LibraryEntity element) =>
250 _isJsInteropLibrary(element); 242 _isJsInteropLibrary(element);
251 243
252 /// Returns `true` if [element] is a JsInterop class. 244 /// Returns `true` if [element] is a JsInterop class.
253 bool isJsInteropClass(ClassElement element) => _isJsInteropClass(element); 245 bool isJsInteropClass(ClassEntity element) => _isJsInteropClass(element);
254 246
255 /// Returns `true` if [element] is a JsInterop method. 247 /// Returns `true` if [element] is a JsInterop method.
256 bool isJsInteropMember(MemberElement element) { 248 bool isJsInteropMember(MemberEntity element) {
257 if (element.isFunction || element.isConstructor || element.isAccessor) { 249 if (element.isFunction ||
258 MethodElement function = element; 250 element.isConstructor ||
251 element.isGetter ||
252 element.isSetter) {
253 FunctionEntity function = element;
259 if (!function.isExternal) return false; 254 if (!function.isExternal) return false;
260 255
261 if (_isJsInteropMember(function)) return true; 256 if (_isJsInteropMember(function)) return true;
262 if (function.isClassMember) { 257 if (function.enclosingClass != null) {
263 return _isJsInteropClass(function.enclosingClass); 258 return _isJsInteropClass(function.enclosingClass);
264 } 259 }
265 if (function.isTopLevel) { 260 if (function.isTopLevel) {
266 return _isJsInteropLibrary(function.library); 261 return _isJsInteropLibrary(function.library);
267 } 262 }
268 return false; 263 return false;
269 } else { 264 } else {
270 return _isJsInteropMember(element); 265 return _isJsInteropMember(element);
271 } 266 }
272 } 267 }
273 268
274 /// Returns `true` if the name of [element] is fixed for the generated 269 /// Returns `true` if the name of [element] is fixed for the generated
275 /// JavaScript. 270 /// JavaScript.
276 bool hasFixedBackendName(MemberElement element) { 271 bool hasFixedBackendName(MemberEntity element) {
277 return isJsInteropMember(element) || 272 return isJsInteropMember(element) || nativeMemberName.containsKey(element);
278 nativeMemberName.containsKey(element.declaration);
279 } 273 }
280 274
281 /// Computes the name for [element] to use in the generated JavaScript. This 275 /// Computes the name for [element] to use in the generated JavaScript. This
282 /// is either given through a native annotation or a js interop annotation. 276 /// is either given through a native annotation or a js interop annotation.
283 String getFixedBackendName(MemberElement element) { 277 String getFixedBackendName(MemberEntity element) {
284 String name = nativeMemberName[element.declaration]; 278 String name = nativeMemberName[element];
285 if (name == null && isJsInteropMember(element)) { 279 if (name == null && isJsInteropMember(element)) {
286 // If an element isJsInterop but _isJsInterop is false that means it is 280 // If an element isJsInterop but _isJsInterop is false that means it is
287 // considered interop as the parent class is interop. 281 // considered interop as the parent class is interop.
288 name = element.isConstructor 282 name = element.isConstructor
289 ? _jsClassNameHelper(element.enclosingClass) 283 ? _jsClassNameHelper(element.enclosingClass)
290 : _jsMemberNameHelper(element); 284 : _jsMemberNameHelper(element);
291 nativeMemberName[element.declaration] = name; 285 nativeMemberName[element] = name;
292 } 286 }
293 return name; 287 return name;
294 } 288 }
295 289
296 String _jsLibraryNameHelper(LibraryElement element) { 290 String _jsLibraryNameHelper(LibraryEntity element) {
297 String jsInteropName = getJsInteropLibraryName(element); 291 String jsInteropName = getJsInteropLibraryName(element);
298 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName; 292 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
299 return 'self'; 293 return 'self';
300 } 294 }
301 295
302 String _jsClassNameHelper(ClassElement element) { 296 String _jsClassNameHelper(ClassEntity element) {
303 String jsInteropName = getJsInteropClassName(element); 297 String jsInteropName = getJsInteropClassName(element);
304 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName; 298 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName;
305 return computeUnescapedJSInteropName(element.name); 299 return computeUnescapedJSInteropName(element.name);
306 } 300 }
307 301
308 String _jsMemberNameHelper(MemberElement element) { 302 String _jsMemberNameHelper(MemberEntity element) {
309 String jsInteropName = jsInteropMemberNames[element]; 303 String jsInteropName = jsInteropMemberNames[element];
310 assert(invariant(element, 304 assert(invariant(element,
311 !(jsInteropMemberNames.containsKey(element) && jsInteropName == null), 305 !(jsInteropMemberNames.containsKey(element) && jsInteropName == null),
312 message: 306 message:
313 'Member $element is js interop but js interop name has not yet ' 307 'Member $element is js interop but js interop name has not yet '
314 'been computed.')); 308 'been computed.'));
315 if (jsInteropName != null && jsInteropName.isNotEmpty) { 309 if (jsInteropName != null && jsInteropName.isNotEmpty) {
316 return jsInteropName; 310 return jsInteropName;
317 } 311 }
318 return computeUnescapedJSInteropName(element.name); 312 return computeUnescapedJSInteropName(element.name);
319 } 313 }
320 314
321 /// Returns a JavaScript path specifying the context in which 315 /// Returns a JavaScript path specifying the context in which
322 /// [element.fixedBackendName] should be evaluated. Only applicable for 316 /// [element.fixedBackendName] should be evaluated. Only applicable for
323 /// elements using typed JavaScript interop. 317 /// elements using typed JavaScript interop.
324 /// For example: fixedBackendPath for the static method createMap in the 318 /// For example: fixedBackendPath for the static method createMap in the
325 /// Map class of the goog.map JavaScript library would have path 319 /// Map class of the goog.map JavaScript library would have path
326 /// "goog.maps.Map". 320 /// "goog.maps.Map".
327 String getFixedBackendMethodPath(MethodElement element) { 321 String getFixedBackendMethodPath(FunctionEntity element) {
328 if (!isJsInteropMember(element)) return null; 322 if (!isJsInteropMember(element)) return null;
329 if (element.isInstanceMember) return 'this'; 323 if (element.isInstanceMember) return 'this';
330 if (element.isConstructor) { 324 if (element.isConstructor) {
331 return _fixedBackendClassPath(element.enclosingClass); 325 return _fixedBackendClassPath(element.enclosingClass);
332 } 326 }
333 StringBuffer sb = new StringBuffer(); 327 StringBuffer sb = new StringBuffer();
334 sb.write(_jsLibraryNameHelper(element.library)); 328 sb.write(_jsLibraryNameHelper(element.library));
335 if (element.enclosingClass != null) { 329 if (element.enclosingClass != null) {
336 sb..write('.')..write(_jsClassNameHelper(element.enclosingClass)); 330 sb..write('.')..write(_jsClassNameHelper(element.enclosingClass));
337 } 331 }
338 return sb.toString(); 332 return sb.toString();
339 } 333 }
340 334
341 String _fixedBackendClassPath(ClassElement element) { 335 String _fixedBackendClassPath(ClassEntity element) {
342 if (!isJsInteropClass(element)) return null; 336 if (!isJsInteropClass(element)) return null;
343 return _jsLibraryNameHelper(element.library); 337 return _jsLibraryNameHelper(element.library);
344 } 338 }
345 339
346 /// Returns `true` if [cls] is a native class. 340 /// Returns `true` if [cls] is a native class.
347 bool isNativeClass(ClassElement element) { 341 bool isNativeClass(ClassEntity element) {
348 if (isJsInteropClass(element)) return true; 342 if (isJsInteropClass(element)) return true;
349 return nativeClassTagInfo.containsKey(element); 343 return nativeClassTagInfo.containsKey(element);
350 } 344 }
351 345
352 /// Returns `true` if [element] is a native member of a native class. 346 /// Returns `true` if [element] is a native member of a native class.
353 bool isNativeMember(MemberElement element) { 347 bool isNativeMember(MemberEntity element) {
354 if (isJsInteropMember(element)) return true; 348 if (isJsInteropMember(element)) return true;
355 return nativeMemberName.containsKey(element); 349 return nativeMemberName.containsKey(element);
356 } 350 }
357 351
358 /// Returns `true` if [element] or any of its superclasses is native. 352 /// Returns `true` if [element] or any of its superclasses is native.
359 bool isNativeOrExtendsNative(ClassElement element) { 353 bool isNativeOrExtendsNative(ClassElement element) {
360 if (element == null) return false; 354 if (element == null) return false;
361 if (isNativeClass(element) || isJsInteropClass(element)) { 355 if (isNativeClass(element) || isJsInteropClass(element)) {
362 return true; 356 return true;
363 } 357 }
364 assert(element.isResolved); 358 assert(element.isResolved);
365 return isNativeOrExtendsNative(element.superclass); 359 return isNativeOrExtendsNative(element.superclass);
366 } 360 }
367 361
368 /// Sets the native [name] for the member [element]. This name is used for 362 /// Sets the native [name] for the member [element]. This name is used for
369 /// [element] in the generated JavaScript. 363 /// [element] in the generated JavaScript.
370 void setNativeMemberName(MemberElement element, String name) { 364 void setNativeMemberName(MemberEntity element, String name) {
371 // TODO(johnniwinther): Avoid setting this more than once. The enqueuer 365 // TODO(johnniwinther): Avoid setting this more than once. The enqueuer
372 // might enqueue [element] several times (before processing it) and computes 366 // might enqueue [element] several times (before processing it) and computes
373 // name on each call to `internalAddToWorkList`. 367 // name on each call to `internalAddToWorkList`.
374 assert(invariant( 368 assert(invariant(element,
375 element, 369 nativeMemberName[element] == null || nativeMemberName[element] == name,
376 nativeMemberName[element.declaration] == null ||
377 nativeMemberName[element.declaration] == name,
378 message: "Native member name set inconsistently on $element: " 370 message: "Native member name set inconsistently on $element: "
379 "Existing name '${nativeMemberName[element.declaration]}', " 371 "Existing name '${nativeMemberName[element]}', "
380 "new name '$name'.")); 372 "new name '$name'."));
381 nativeMemberName[element.declaration] = name; 373 nativeMemberName[element] = name;
382 } 374 }
383 375
384 /// Sets the native tag info for [cls]. 376 /// Sets the native tag info for [cls].
385 /// 377 ///
386 /// The tag info string contains comma-separated 'words' which are either 378 /// The tag info string contains comma-separated 'words' which are either
387 /// dispatch tags (having JavaScript identifier syntax) and directives that 379 /// dispatch tags (having JavaScript identifier syntax) and directives that
388 /// begin with `!`. 380 /// begin with `!`.
389 void setNativeClassTagInfo(ClassElement cls, String tagInfo) { 381 void setNativeClassTagInfo(ClassEntity cls, String tagInfo) {
390 // TODO(johnniwinther): Assert that this is only called once. The memory 382 // TODO(johnniwinther): Assert that this is only called once. The memory
391 // compiler copies pre-processed elements into a new compiler through 383 // compiler copies pre-processed elements into a new compiler through
392 // [Compiler.onLibraryScanned] and thereby causes multiple calls to this 384 // [Compiler.onLibraryScanned] and thereby causes multiple calls to this
393 // method. 385 // method.
394 assert(invariant( 386 assert(invariant(cls,
395 cls, 387 nativeClassTagInfo[cls] == null || nativeClassTagInfo[cls] == tagInfo,
396 nativeClassTagInfo[cls.declaration] == null ||
397 nativeClassTagInfo[cls.declaration] == tagInfo,
398 message: "Native tag info set inconsistently on $cls: " 388 message: "Native tag info set inconsistently on $cls: "
399 "Existing tag info '${nativeClassTagInfo[cls.declaration]}', " 389 "Existing tag info '${nativeClassTagInfo[cls]}', "
400 "new tag info '$tagInfo'.")); 390 "new tag info '$tagInfo'."));
401 nativeClassTagInfo[cls.declaration] = tagInfo; 391 nativeClassTagInfo[cls] = tagInfo;
402 } 392 }
403 393
404 /// Returns the list of native tag words for [cls]. 394 /// Returns the list of native tag words for [cls].
405 List<String> getNativeTagsOfClassRaw(ClassElement cls) { 395 List<String> getNativeTagsOfClassRaw(ClassEntity cls) {
406 String quotedName = nativeClassTagInfo[cls.declaration]; 396 String quotedName = nativeClassTagInfo[cls];
407 return quotedName.substring(1, quotedName.length - 1).split(','); 397 return quotedName.substring(1, quotedName.length - 1).split(',');
408 } 398 }
409 399
410 /// Returns the list of non-directive native tag words for [cls]. 400 /// Returns the list of non-directive native tag words for [cls].
411 List<String> getNativeTagsOfClass(ClassElement cls) { 401 List<String> getNativeTagsOfClass(ClassEntity cls) {
412 return getNativeTagsOfClassRaw(cls) 402 return getNativeTagsOfClassRaw(cls)
413 .where((s) => !s.startsWith('!')) 403 .where((s) => !s.startsWith('!'))
414 .toList(); 404 .toList();
415 } 405 }
416 406
417 /// Returns `true` if [cls] has a `!nonleaf` tag word. 407 /// Returns `true` if [cls] has a `!nonleaf` tag word.
418 bool hasNativeTagsForcedNonLeaf(ClassElement cls) { 408 bool hasNativeTagsForcedNonLeaf(ClassEntity cls) {
419 return getNativeTagsOfClassRaw(cls).contains('!nonleaf'); 409 return getNativeTagsOfClassRaw(cls).contains('!nonleaf');
420 } 410 }
421 411
422 /// Returns the [NativeBehavior] for calling the native [method]. 412 /// Returns the [NativeBehavior] for calling the native [method].
423 NativeBehavior getNativeMethodBehavior(MethodElement method) { 413 NativeBehavior getNativeMethodBehavior(FunctionEntity method) {
424 assert(invariant(method, nativeMethodBehavior.containsKey(method), 414 assert(invariant(method, nativeMethodBehavior.containsKey(method),
425 message: "No native method behavior has been computed for $method.")); 415 message: "No native method behavior has been computed for $method."));
426 return nativeMethodBehavior[method]; 416 return nativeMethodBehavior[method];
427 } 417 }
428 418
429 /// Returns the [NativeBehavior] for reading from the native [field]. 419 /// Returns the [NativeBehavior] for reading from the native [field].
430 NativeBehavior getNativeFieldLoadBehavior(FieldElement field) { 420 NativeBehavior getNativeFieldLoadBehavior(FieldEntity field) {
431 assert(invariant(field, nativeFieldLoadBehavior.containsKey(field), 421 assert(invariant(field, nativeFieldLoadBehavior.containsKey(field),
432 message: "No native field load behavior has been " 422 message: "No native field load behavior has been "
433 "computed for $field.")); 423 "computed for $field."));
434 return nativeFieldLoadBehavior[field]; 424 return nativeFieldLoadBehavior[field];
435 } 425 }
436 426
437 /// Returns the [NativeBehavior] for writing to the native [field]. 427 /// Returns the [NativeBehavior] for writing to the native [field].
438 NativeBehavior getNativeFieldStoreBehavior(FieldElement field) { 428 NativeBehavior getNativeFieldStoreBehavior(FieldEntity field) {
439 assert(invariant(field, nativeFieldStoreBehavior.containsKey(field), 429 assert(invariant(field, nativeFieldStoreBehavior.containsKey(field),
440 message: "No native field store behavior has been " 430 message: "No native field store behavior has been "
441 "computed for $field.")); 431 "computed for $field."));
442 return nativeFieldStoreBehavior[field]; 432 return nativeFieldStoreBehavior[field];
443 } 433 }
444 434
445 /// Registers the [behavior] for calling the native [method]. 435 /// Registers the [behavior] for calling the native [method].
446 void setNativeMethodBehavior(MethodElement method, NativeBehavior behavior) { 436 void setNativeMethodBehavior(FunctionEntity method, NativeBehavior behavior) {
447 nativeMethodBehavior[method] = behavior; 437 nativeMethodBehavior[method] = behavior;
448 } 438 }
449 439
450 /// Registers the [behavior] for reading from the native [field]. 440 /// Registers the [behavior] for reading from the native [field].
451 void setNativeFieldLoadBehavior(FieldElement field, NativeBehavior behavior) { 441 void setNativeFieldLoadBehavior(FieldEntity field, NativeBehavior behavior) {
452 nativeFieldLoadBehavior[field] = behavior; 442 nativeFieldLoadBehavior[field] = behavior;
453 } 443 }
454 444
455 /// Registers the [behavior] for writing to the native [field]. 445 /// Registers the [behavior] for writing to the native [field].
456 void setNativeFieldStoreBehavior( 446 void setNativeFieldStoreBehavior(FieldEntity field, NativeBehavior behavior) {
457 FieldElement field, NativeBehavior behavior) {
458 nativeFieldStoreBehavior[field] = behavior; 447 nativeFieldStoreBehavior[field] = behavior;
459 } 448 }
460 449
461 /// Apply JS$ escaping scheme to convert possible escaped Dart names into 450 /// Apply JS$ escaping scheme to convert possible escaped Dart names into
462 /// JS names. 451 /// JS names.
463 String computeUnescapedJSInteropName(String name) { 452 String computeUnescapedJSInteropName(String name) {
464 return name.startsWith(_jsInteropEscapePrefix) 453 return name.startsWith(_jsInteropEscapePrefix)
465 ? name.substring(_jsInteropEscapePrefix.length) 454 ? name.substring(_jsInteropEscapePrefix.length)
466 : name; 455 : name;
467 } 456 }
468 } 457 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698