OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of html; | 5 part of html; |
6 | 6 |
7 class _Property { | |
8 _Property(this.name) : | |
9 _hasValue = false, | |
10 writable = false, | |
11 isMethod = false, | |
12 isOwn = true, | |
13 wasThrown = false; | |
14 | |
15 bool get hasValue => _hasValue; | |
16 get value => _value; | |
17 set value(v) { | |
18 _value = v; | |
19 _hasValue = true; | |
20 } | |
21 | |
22 final String name; | |
23 Function setter; | |
24 Function getter; | |
25 var _value; | |
26 bool _hasValue; | |
27 bool writable; | |
28 bool isMethod; | |
29 bool isOwn; | |
30 bool wasThrown; | |
31 } | |
32 | |
7 class _ConsoleVariables { | 33 class _ConsoleVariables { |
8 Map<String, Object> _data = new Map<String, Object>(); | 34 Map<String, Object> _data = new Map<String, Object>(); |
9 | 35 |
10 /** | 36 /** |
11 * Forward member accesses to the backing JavaScript object. | 37 * Forward member accesses to the backing JavaScript object. |
12 */ | 38 */ |
13 noSuchMethod(Invocation invocation) { | 39 noSuchMethod(Invocation invocation) { |
14 String member = MirrorSystem.getName(invocation.memberName); | 40 String member = MirrorSystem.getName(invocation.memberName); |
15 if (invocation.isGetter) { | 41 if (invocation.isGetter) { |
16 return _data[member]; | 42 return _data[member]; |
17 } else if (invocation.isSetter) { | 43 } else if (invocation.isSetter) { |
18 assert(member.endsWith('=')); | 44 assert(member.endsWith('=')); |
19 member = member.substring(0, member.length - 1); | 45 member = member.substring(0, member.length - 1); |
20 _data[member] = invocation.positionalArguments[0]; | 46 _data[member] = invocation.positionalArguments[0]; |
21 } else { | 47 } else { |
22 return Function.apply(_data[member], invocation.positionalArguments, invoc ation.namedArguments); | 48 return Function.apply(_data[member], invocation.positionalArguments, invoc ation.namedArguments); |
23 } | 49 } |
24 } | 50 } |
25 | 51 |
26 void clear() => _data.clear(); | 52 void clear() => _data.clear(); |
27 | 53 |
28 /** | 54 /** |
29 * List all variables currently defined. | 55 * List all variables currently defined. |
30 */ | 56 */ |
31 List variables() => _data.keys.toList(growable: false); | 57 List variables() => _data.keys.toList(growable: false); |
32 } | 58 } |
33 | 59 |
60 /** | |
61 * Base class for invocation trampolines used to closurize methods, getters | |
62 * and setters. | |
63 */ | |
64 abstract class _Trampoline implements Function { | |
65 final ObjectMirror _receiver; | |
66 final MethodMirror _methodMirror; | |
67 final Symbol _selector; | |
68 | |
69 _Trampoline(this._receiver, this._methodMirror, this._selector); | |
70 } | |
71 | |
72 class _MethodTrampoline extends _Trampoline { | |
73 _MethodTrampoline(ObjectMirror receiver, MethodMirror methodMirror, Symbol sel ector) : | |
Leaf
2014/05/07 01:47:27
line width?
Jacob
2014/05/07 20:57:08
Done.
| |
74 super(receiver, methodMirror, selector); | |
75 | |
76 noSuchMethod(Invocation msg) { | |
77 if (msg.memberName != #call) return super.noSuchMethod(msg); | |
78 return _receiver.invoke(_selector, | |
79 msg.positionalArguments, | |
80 msg.namedArguments).reflectee; | |
81 } | |
82 } | |
83 | |
84 /** | |
85 * Invocation trampoline class used to closurize getters. | |
86 */ | |
87 class _GetterTrampoline extends _Trampoline { | |
88 _GetterTrampoline(ObjectMirror receiver, MethodMirror methodMirror, Symbol sel ector) : | |
Leaf
2014/05/07 01:47:27
ditto
Jacob
2014/05/07 20:57:08
Done.
| |
89 super(receiver, methodMirror, selector); | |
90 | |
91 call() => _receiver.getField(_selector).reflectee; | |
92 } | |
93 | |
94 /** | |
95 * Invocation trampoline class used to closurize setters. | |
96 */ | |
97 class _SetterTrampoline extends _Trampoline { | |
98 _SetterTrampoline(ObjectMirror receiver, MethodMirror methodMirror, Symbol sel ector) : | |
Leaf
2014/05/07 01:47:27
also
Jacob
2014/05/07 20:57:08
Done.
| |
99 super(receiver, methodMirror, selector); | |
100 | |
101 call(value) { | |
102 _receiver.setField(_selector, value); | |
103 } | |
104 } | |
105 | |
34 class _Utils { | 106 class _Utils { |
35 static double dateTimeToDouble(DateTime dateTime) => | 107 static double dateTimeToDouble(DateTime dateTime) => |
36 dateTime.millisecondsSinceEpoch.toDouble(); | 108 dateTime.millisecondsSinceEpoch.toDouble(); |
37 static DateTime doubleToDateTime(double dateTime) { | 109 static DateTime doubleToDateTime(double dateTime) { |
38 try { | 110 try { |
39 return new DateTime.fromMillisecondsSinceEpoch(dateTime.toInt()); | 111 return new DateTime.fromMillisecondsSinceEpoch(dateTime.toInt()); |
40 } catch(_) { | 112 } catch(_) { |
41 // TODO(antonnm): treat exceptions properly in bindings and | 113 // TODO(antonnm): treat exceptions properly in bindings and |
42 // find out how to treat NaNs. | 114 // find out how to treat NaNs. |
43 return null; | 115 return null; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 var map = {}; | 209 var map = {}; |
138 for (int i = 0; i < localVariables.length; i+=2) { | 210 for (int i = 0; i < localVariables.length; i+=2) { |
139 map[stripMemberName(localVariables[i])] = localVariables[i+1]; | 211 map[stripMemberName(localVariables[i])] = localVariables[i+1]; |
140 } | 212 } |
141 return map; | 213 return map; |
142 } | 214 } |
143 | 215 |
144 static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables(); | 216 static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables(); |
145 | 217 |
146 /** | 218 /** |
147 * Header passed in from the Dartium Developer Tools when an expression is | |
148 * evaluated in the console as opposed to the watch window or another context | |
149 * that does not expect REPL support. | |
150 */ | |
151 static const _CONSOLE_API_SUPPORT_HEADER = | |
152 'with ((console && console._commandLineAPI) || { __proto__: null }) {\n'; | |
153 static bool expectsConsoleApi(String expression) { | |
154 return expression.indexOf(_CONSOLE_API_SUPPORT_HEADER) == 0;; | |
155 } | |
156 | |
157 /** | |
158 * Takes an [expression] and a list of [local] variable and returns an | 219 * Takes an [expression] and a list of [local] variable and returns an |
159 * expression for a closure with a body matching the original expression | 220 * expression for a closure with a body matching the original expression |
160 * where locals are passed in as arguments. Returns a list containing the | 221 * where locals are passed in as arguments. Returns a list containing the |
161 * String expression for the closure and the list of arguments that should | 222 * String expression for the closure and the list of arguments that should |
162 * be passed to it. The expression should then be evaluated using | 223 * be passed to it. The expression should then be evaluated using |
163 * Dart_EvaluateExpr which will generate a closure that should be invoked | 224 * Dart_EvaluateExpr which will generate a closure that should be invoked |
164 * with the list of arguments passed to this method. | 225 * with the list of arguments passed to this method. |
165 * | 226 * |
166 * For example: | 227 * For example: |
167 * <code> | 228 * <code> |
168 * _consoleTempVariables = {'a' : someValue, 'b': someOtherValue} | 229 * _consoleTempVariables = {'a' : someValue, 'b': someOtherValue} |
169 * wrapExpressionAsClosure("${_CONSOLE_API_SUPPORT_HEADER}foo + bar + a", | 230 * wrapExpressionAsClosure("foo + bar + a", ["bar", 40, "foo", 2], true) |
170 * ["bar", 40, "foo", 2]) | |
171 * </code> | 231 * </code> |
172 * will return: | 232 * will return: |
173 * <code> | 233 * <code> |
174 * ["""(final $consoleVariables, final bar, final foo, final a, final b) => | 234 * ["""(final $consoleVariables, final bar, final foo, final a, final b) => |
175 * (foo + bar + a | 235 * (foo + bar + a |
176 * )""", | 236 * )""", |
177 * [_consoleTempVariables, 40, 2, someValue, someOtherValue]] | 237 * [_consoleTempVariables, 40, 2, someValue, someOtherValue]] |
178 * </code> | 238 * </code> |
179 */ | 239 */ |
180 static List wrapExpressionAsClosure(String expression, List locals) { | 240 static List wrapExpressionAsClosure(String expression, List locals, |
181 // FIXME: dartbug.com/10434 find a less fragile way to determine whether | 241 bool includeCommandLineAPI) { |
182 // we need to strip off console API support added by InjectedScript. | |
183 var args = {}; | 242 var args = {}; |
184 var sb = new StringBuffer("("); | 243 var sb = new StringBuffer("("); |
185 addArg(arg, value) { | 244 addArg(arg, value) { |
186 arg = stripMemberName(arg); | 245 arg = stripMemberName(arg); |
187 if (args.containsKey(arg)) return; | 246 if (args.containsKey(arg)) return; |
188 // We ignore arguments with the name 'this' rather than throwing an | 247 // We ignore arguments with the name 'this' rather than throwing an |
189 // exception because Dart_GetLocalVariables includes 'this' and it | 248 // exception because Dart_GetLocalVariables includes 'this' and it |
190 // is more convenient to filter it out here than from C++ code. | 249 // is more convenient to filter it out here than from C++ code. |
191 // 'this' needs to be handled by calling Dart_EvaluateExpr with | 250 // 'this' needs to be handled by calling Dart_EvaluateExpr with |
192 // 'this' as the target rather than by passing it as an argument. | 251 // 'this' as the target rather than by passing it as an argument. |
193 if (arg == 'this') return; | 252 if (arg == 'this') return; |
194 if (args.isNotEmpty) { | 253 if (args.isNotEmpty) { |
195 sb.write(", "); | 254 sb.write(", "); |
196 } | 255 } |
197 sb.write("final $arg"); | 256 sb.write("final $arg"); |
198 args[arg] = value; | 257 args[arg] = value; |
199 } | 258 } |
200 | 259 |
201 if (expectsConsoleApi(expression)) { | 260 if (includeCommandLineAPI) { |
202 expression = expression.substring(expression.indexOf('\n') + 1); | |
203 expression = expression.substring(0, expression.lastIndexOf('\n')); | |
204 | |
205 addArg("\$consoleVariables", _consoleTempVariables); | 261 addArg("\$consoleVariables", _consoleTempVariables); |
206 | 262 |
207 // FIXME: use a real Dart tokenizer. The following regular expressions | 263 // FIXME: use a real Dart tokenizer. The following regular expressions |
208 // only allow setting variables at the immediate start of the expression | 264 // only allow setting variables at the immediate start of the expression |
209 // to limit the number of edge cases we have to handle. | 265 // to limit the number of edge cases we have to handle. |
210 | 266 |
211 // Match expressions that start with "var x" | 267 // Match expressions that start with "var x" |
212 final _VARIABLE_DECLARATION = new RegExp("^(\\s*)var\\s+(\\w+)"); | 268 final _VARIABLE_DECLARATION = new RegExp("^(\\s*)var\\s+(\\w+)"); |
213 // Match expressions that start with "someExistingConsoleVar =" | 269 // Match expressions that start with "someExistingConsoleVar =" |
214 final _SET_VARIABLE = new RegExp("^(\\s*)(\\w+)(\\s*=)"); | 270 final _SET_VARIABLE = new RegExp("^(\\s*)(\\w+)(\\s*=)"); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
251 | 307 |
252 // TODO(jacobr): remove the parentheses around the expresson once | 308 // TODO(jacobr): remove the parentheses around the expresson once |
253 // dartbug.com/13723 is fixed. Currently we wrap expression in parentheses | 309 // dartbug.com/13723 is fixed. Currently we wrap expression in parentheses |
254 // to ensure only valid Dart expressions are allowed. Otherwise the DartVM | 310 // to ensure only valid Dart expressions are allowed. Otherwise the DartVM |
255 // quietly ignores trailing Dart statements resulting in user confusion | 311 // quietly ignores trailing Dart statements resulting in user confusion |
256 // when part of an invalid expression they entered is ignored. | 312 // when part of an invalid expression they entered is ignored. |
257 sb..write(') => (\n$expression\n)'); | 313 sb..write(') => (\n$expression\n)'); |
258 return [sb.toString(), args.values.toList(growable: false)]; | 314 return [sb.toString(), args.values.toList(growable: false)]; |
259 } | 315 } |
260 | 316 |
261 /** | 317 static String _getShortSymbolName(Symbol symbol, |
262 * TODO(jacobr): this is a big hack to get around the fact that we are still | 318 DeclarationMirror declaration) { |
263 * passing some JS expression to the evaluate method even when in a Dart | 319 var name = MirrorSystem.getName(symbol); |
264 * context. | 320 if (declaration is MethodMirror) { |
265 */ | 321 if (declaration.isSetter && name[name.length-1] == "=") { |
266 static bool isJsExpression(String expression) => | 322 return name.substring(0, name.length-1); |
267 expression.startsWith("(function getCompletions"); | 323 } |
268 | 324 if (declaration.isConstructor) { |
269 /** | 325 return name.substring(name.indexOf('.') + 1); |
270 * Returns a list of completions to use if the receiver is o. | 326 } |
271 */ | 327 } |
272 static List<String> getCompletions(o) { | 328 return name; |
273 MirrorSystem system = currentMirrorSystem(); | 329 } |
274 var completions = new Set<String>(); | 330 |
275 addAll(Map<Symbol, dynamic> map, bool isStatic) { | 331 /** |
276 map.forEach((symbol, mirror) { | 332 * Adds all candidate String completitions from [declarations] to [output] |
277 if (mirror.isStatic == isStatic && !mirror.isPrivate) { | 333 * filtering based on [staticContext] and [includePrivate]. |
334 */ | |
335 static void _getCompletionsHelper(ClassMirror classMirror, | |
336 bool staticContext, bool includePrivate, Set<String> output) { | |
337 classMirror.declarations.forEach((symbol, declaration) { | |
338 if (!includePrivate && declaration.isPrivate) return; | |
339 if (declaration is VariableMirror) { | |
340 if (staticContext != declaration.isStatic) return; | |
341 } else if (declaration is MethodMirror) { | |
342 if (staticContext != declaration.isStatic) return; | |
rmacnak
2014/05/06 21:14:43
Should do this check after considering constructor
Jacob
2014/05/07 00:05:24
Good catch! I added a test (see utils.dart in the
| |
343 if (declaration.isOperator) return; | |
rmacnak
2014/05/06 21:14:43
Because the completions assume dot notation?
Jacob
2014/05/07 00:05:24
Correct. Completions are after a dot.
| |
344 if (declaration.isConstructor) { | |
345 var name = MirrorSystem.getName(declaration.constructorName); | |
346 if (name.isNotEmpty) output.add(name); | |
347 return; | |
348 } | |
349 } else if (declaration is TypeMirror) { | |
350 return; | |
351 } | |
352 output.add(_getShortSymbolName(symbol, declaration)); | |
353 }); | |
354 } | |
355 | |
356 static void _getLibraryCompletionsHelper( | |
357 LibraryMirror library, bool includePrivate, Set<String> output) { | |
358 library.declarations.forEach((symbol, declaration) { | |
rmacnak
2014/05/06 21:14:43
Add the prefixed imports (but not their declaratio
Jacob
2014/05/07 00:05:24
Correct. Interesting idea to show all completions.
| |
359 if (!includePrivate && declaration.isPrivate) return; | |
360 output.add(_getShortSymbolName(symbol, declaration)); | |
361 }); | |
362 } | |
363 | |
364 static LibraryMirror getLibraryMirror(String url) => | |
365 currentMirrorSystem().libraries[Uri.parse(url)]; | |
366 | |
367 /** | |
368 * Get code completions for [o] only showing privates from [libraryUrl]. | |
369 */ | |
370 static List<String> getObjectCompletions(o, String libraryUrl) { | |
371 var classMirror; | |
372 bool staticContext; | |
373 if (o is Type) { | |
374 classMirror = reflectClass(o); | |
375 staticContext = true; | |
376 } else { | |
377 classMirror = reflect(o).type; | |
378 staticContext = false; | |
379 } | |
380 var names = new Set<String>(); | |
381 getClassCompletions(classMirror, names, staticContext, libraryUrl); | |
382 return names.toList()..sort(); | |
383 } | |
384 | |
385 static void getClassCompletions(ClassMirror classMirror, Set<String> names, | |
386 bool staticContext, String libraryUrl) { | |
387 LibraryMirror libraryMirror = getLibraryMirror(libraryUrl); | |
388 if (!staticContext) { | |
389 for (var interface in classMirror.superinterfaces) { | |
rmacnak
2014/05/06 21:14:43
Interfaces declared on superclasses?
Jacob
2014/05/07 00:05:24
Fixed.
| |
390 _getCompletionsHelper(interface, staticContext, | |
391 libraryMirror == interface.owner, names); | |
392 } | |
393 } | |
394 while (classMirror != null) { | |
395 _getCompletionsHelper(classMirror, staticContext, | |
396 libraryMirror == classMirror.owner, names); | |
397 // Do not walk up the superclass tree when displaying statics. | |
398 if (staticContext) break; | |
399 classMirror = classMirror.superclass; | |
400 } | |
401 } | |
402 | |
403 static List<String> getLibraryCompletions(String url) { | |
404 var names = new Set<String>(); | |
405 _getLibraryCompletionsHelper(getLibraryMirror(url), true, names); | |
406 return names.toList(); | |
407 } | |
408 | |
409 /** | |
410 * Get valid code completitions from within a library and all libraries | |
411 * imported by that library. | |
412 */ | |
413 static List<String> getLibraryCompletionsIncludingImports(String url) { | |
414 var names = new Set<String>(); | |
415 var libraryMirror = getLibraryMirror(url); | |
416 _getLibraryCompletionsHelper(libraryMirror, true, names); | |
417 for (var dependency in libraryMirror.libraryDependencies) { | |
418 if (dependency.isImport) { | |
419 if (dependency.prefix == null) { | |
420 _getLibraryCompletionsHelper(dependency.targetLibrary, false, names); | |
421 } else { | |
422 names.add(MirrorSystem.getName(dependency.prefix)); | |
423 } | |
424 } | |
425 } | |
426 return names.toList(); | |
427 } | |
428 | |
429 /** | |
430 * For parity with the JavaScript debugger, we treat some getters as if | |
431 * they are fields so that users can see their values immediately. | |
432 * This matches JavaScript's behavior for getters on DOM objects. | |
433 * In the future we should consider adding an annotation to tag getters | |
434 * in user libraries as side effect free. | |
435 */ | |
436 static bool _isSideEffectFreeGetter(MethodMirror methodMirror) { | |
437 var owner = methodMirror.owner; | |
438 var libraryMirror; | |
439 if (owner is ClassMirror) { | |
440 libraryMirror = owner.owner; | |
Leaf
2014/05/07 01:47:27
Does this do the right thing if the class is produ
rmacnak
2014/05/07 16:59:51
A class's owner will always be a library.
Jacob
2014/05/07 20:57:08
yep.
| |
441 } else if (owner is LibraryMirror) { | |
442 libraryMirror = owner; | |
443 } | |
444 if (libraryMirror != null) { | |
445 var libraryUrl = MirrorSystem.getName(libraryMirror.qualifiedName); | |
rmacnak
2014/05/06 21:14:43
You're not comparing the url here. The qualified n
Jacob
2014/05/07 00:05:24
Tweaked to actually use the URI instead.
| |
446 // This matches JavaScript behavior. We should consider displaying | |
447 // getters for all dart platform libraries rather than just dart.dom. | |
rmacnak
2014/05/06 21:14:43
I wouldn't do this for all Dart platform libraries
Jacob
2014/05/07 00:05:24
Makes sense. I think the right solution is to pro
| |
448 if (libraryUrl.startsWith("dart.dom.")) | |
449 return true; | |
450 } | |
451 return false; | |
452 } | |
453 | |
454 /** | |
455 * Whether we should treat a property as a field for the purposes of the | |
456 * debugger. | |
457 */ | |
458 static bool treatPropertyAsField(MethodMirror methodMirror) => | |
459 (methodMirror.isGetter || methodMirror.isSetter) && | |
460 (methodMirror.isSynthetic || _isSideEffectFreeGetter(methodMirror)); | |
461 | |
462 // TODO(jacobr): generate more concise function descriptions instead of | |
463 // dumping the entire function source. | |
464 static String describeFunction(function) { | |
465 if (function is _Trampoline) return function._methodMirror.source; | |
466 try { | |
467 return reflect(function).function.source; | |
468 } catch (e) { | |
469 return function.toString(); | |
470 } | |
471 } | |
472 | |
473 static List getInvocationTrampolineDetails(_Trampoline method) { | |
474 var loc = method._methodMirror.location; | |
475 return [loc.line, loc.column, loc.sourceUri.toString(), | |
476 MirrorSystem.getName(method._selector)]; | |
477 } | |
478 | |
479 static List getLibraryProperties(String libraryUrl, bool ownProperties, | |
480 bool accessorPropertiesOnly) { | |
481 var properties = new Map<String, _Property>(); | |
482 var libraryMirror = getLibraryMirror(libraryUrl); | |
483 _addInstanceMirrors(libraryMirror, libraryMirror, | |
484 libraryMirror.declarations, | |
485 ownProperties, accessorPropertiesOnly, false, false, | |
486 properties); | |
487 if (!accessorPropertiesOnly) { | |
488 // We need to add class properties for all classes in the library. | |
489 libraryMirror.declarations.forEach((symbol, declarationMirror) { | |
490 if (declarationMirror is ClassMirror) { | |
278 var name = MirrorSystem.getName(symbol); | 491 var name = MirrorSystem.getName(symbol); |
279 if (mirror is MethodMirror && mirror.isSetter) | 492 if (declarationMirror.hasReflectedType |
280 name = name.substring(0, name.length - 1); | 493 && !properties.containsKey(name)) { |
281 completions.add(name); | 494 properties[name] = new _Property(name) |
495 ..value = declarationMirror.reflectedType; | |
Leaf
2014/05/07 01:47:27
Is this idiomatic in Dart? I'm presuming that thi
Jacob
2014/05/07 20:57:08
This is the idiomatic way to use Dart cascades. A
Leaf
2014/05/08 04:04:01
Ok, I'll get used to it.
On 2014/05/07 20:57:08,
| |
496 } | |
282 } | 497 } |
283 }); | 498 }); |
284 } | 499 } |
285 | 500 return packageProperties(properties); |
286 addForClass(ClassMirror mirror, bool isStatic) { | 501 } |
287 if (mirror == null) | 502 |
503 static List getObjectProperties(o, bool ownProperties, | |
504 bool accessorPropertiesOnly) { | |
505 var properties = new Map<String, _Property>(); | |
506 var names = new Set<String>(); | |
507 var objectMirror = reflect(o); | |
508 var classMirror = objectMirror.type; | |
509 _addInstanceMirrors(objectMirror, classMirror.owner, | |
Leaf
2014/05/07 01:47:27
Same question as before about class mirror owners
Jacob
2014/05/07 20:57:08
Same answer as before. the owner is a library.
| |
510 classMirror.instanceMembers, | |
511 ownProperties, accessorPropertiesOnly, false, true, | |
512 properties); | |
513 return packageProperties(properties); | |
514 } | |
515 | |
516 static List getObjectClassProperties(o, bool ownProperties, | |
517 bool accessorPropertiesOnly) { | |
518 var properties = new Map<String, _Property>(); | |
519 var objectMirror = reflect(o); | |
520 var classMirror = objectMirror.type; | |
521 _addInstanceMirrors(objectMirror, classMirror.owner, | |
Leaf
2014/05/07 01:47:27
ditto
Jacob
2014/05/07 20:57:08
same answer as other case.
| |
522 classMirror.instanceMembers, | |
523 ownProperties, accessorPropertiesOnly, true, false, | |
524 properties); | |
525 _addStatics(classMirror, properties, accessorPropertiesOnly); | |
526 return packageProperties(properties); | |
527 } | |
528 | |
529 static List getClassProperties(Type t, bool ownProperties, | |
530 bool accessorPropertiesOnly) { | |
531 var properties = new Map<String, _Property>(); | |
532 var classMirror = reflectClass(t); | |
533 _addStatics(classMirror, properties, accessorPropertiesOnly); | |
534 return packageProperties(properties); | |
535 } | |
536 | |
537 static void _addStatics(ClassMirror classMirror, | |
538 Map<String, _Property> properties, | |
539 bool accessorPropertiesOnly) { | |
540 classMirror.declarations.forEach((symbol, declaration) { | |
541 var name = _getShortSymbolName(symbol, declaration); | |
542 if (declaration is VariableMirror) { | |
543 if (accessorPropertiesOnly) return; | |
544 if (!declaration.isStatic) return; | |
545 properties.putIfAbsent(name, () => new _Property(name)) | |
546 ..value = classMirror.getField(symbol).reflectee | |
547 ..writable = declaration.isFinal && !declaration.isConst; | |
Leaf
2014/05/07 01:47:27
I don't understand this line (possibly my fault).
Jacob
2014/05/07 20:57:08
I don't understand what I was thinking either. The
| |
548 } else if (declaration is MethodMirror) { | |
549 MethodMirror methodMirror = declaration; | |
550 // FIXMEDART: should we display constructors? | |
551 if (methodMirror.isConstructor) return; | |
552 if (!methodMirror.isStatic) return; | |
553 if (accessorPropertiesOnly) { | |
554 if (methodMirror.isRegularMethod || | |
555 treatPropertyAsField(methodMirror)) { | |
556 return; | |
557 } | |
558 } else if (!methodMirror.isRegularMethod && | |
559 !treatPropertyAsField(methodMirror)) { | |
560 return; | |
561 } | |
562 var property = properties.putIfAbsent(name, () => new _Property(name)); | |
Leaf
2014/05/07 01:47:27
I'm not sure I get why this is right. If I unders
rmacnak
2014/05/07 16:59:51
Implicit getters and setters are not part of Class
Jacob
2014/05/07 20:57:08
Correct. That is why I have to add these cases.
| |
563 if (methodMirror.isRegularMethod) { | |
564 property | |
565 ..value = new _MethodTrampoline(classMirror, methodMirror, symbol) | |
566 ..isMethod = true; | |
567 } else if (methodMirror.isGetter) { | |
568 if (treatPropertyAsField(methodMirror)) { | |
569 try { | |
570 property.value = classMirror.getField(symbol).reflectee; | |
571 } catch (e) { | |
572 property | |
573 ..wasThrown = true | |
574 ..value = e; | |
575 } | |
576 } else if (accessorPropertiesOnly) { | |
577 property.getter = new _GetterTrampoline(classMirror, | |
578 methodMirror, symbol); | |
579 } | |
580 } else if (methodMirror.isSetter) { | |
581 if (accessorPropertiesOnly && !treatPropertyAsField(methodMirror)) { | |
582 property.setter = new _SetterTrampoline(classMirror, | |
583 methodMirror, classMirror.owner); | |
584 } | |
585 property.writable = true; | |
586 } | |
587 } | |
588 }); | |
589 } | |
590 | |
591 /** | |
592 * Helper method that handles collecting up properties from classes | |
593 * or libraries using the filters [ownProperties], [accessorPropertiesOnly], | |
594 * [hideFields], and [hideMethods] to determine which properties are | |
595 * collected. [accessorPropertiesOnly] specifies whether all properties | |
596 * should be returned or just accessors. [hideFields] specifies whether | |
597 * fields should be hidden. hideMethods specifies whether methods should be | |
598 * shown or hidden. [ownProperties] is not currently used but is part of the | |
599 * Blink devtools API for enumerating properties. | |
600 */ | |
601 static void _addInstanceMirrors( | |
602 ObjectMirror objectMirror, | |
603 LibraryMirror libraryMirror, | |
604 Map<Symbol, Mirror> declarations, | |
605 bool ownProperties, bool accessorPropertiesOnly, | |
606 bool hideFields, bool hideMethods, | |
607 Map<String, _Property> properties) { | |
608 declarations.forEach((Symbol symbol, Mirror declaration) { | |
609 if (declaration is TypedefMirror || declaration is ClassMirror) return; | |
610 var name = _getShortSymbolName(symbol, declaration); | |
611 bool isField = declaration is VariableMirror || | |
612 (declaration is MethodMirror && treatPropertyAsField(declaration)); | |
613 if ((isField && hideFields) || (hideMethods && !isField)) return; | |
614 if (accessorPropertiesOnly) { | |
615 if (declaration is ClassMirror || declaration is VariableMirror || | |
Leaf
2014/05/07 01:47:27
declaration is known not to be ClassMirror here.
Jacob
2014/05/07 20:57:08
Fixed. I originally tried to use this method for b
| |
616 declaration.isRegularMethod || isField) { | |
617 return; | |
618 } | |
619 } else if (declaration is MethodMirror && | |
620 (declaration.isGetter || declaration.isSetter) && | |
621 !treatPropertyAsField(declaration)) { | |
288 return; | 622 return; |
289 addAll(mirror.declarations, isStatic); | 623 } |
290 if (mirror.superclass != null) | 624 var property = properties.putIfAbsent(name, () => new _Property(name)); |
291 addForClass(mirror.superclass, isStatic); | 625 if (declaration is VariableMirror) { |
292 for (var interface in mirror.superinterfaces) { | 626 property.value = objectMirror.getField(symbol).reflectee; |
293 addForClass(interface, isStatic); | 627 property.writable = !declaration.isFinal && !declaration.isConst; |
294 } | 628 } else if (declaration is ClassMirror) { |
Leaf
2014/05/07 01:47:27
Again, known to be false.
Jacob
2014/05/07 20:57:08
Done.
| |
295 } | 629 property.value = declaration.runtimeType; |
296 | 630 } else if (declaration.isRegularMethod) { |
Leaf
2014/05/07 01:47:27
The section from here to the end is pretty close t
Jacob
2014/05/07 20:57:08
Done.
| |
297 if (o is Type) { | 631 property.value = new _MethodTrampoline(objectMirror, |
298 addForClass(reflectClass(o), true); | 632 declaration, symbol); |
299 } else { | 633 property.isMethod = true; |
300 addForClass(reflect(o).type, false); | 634 } else if (declaration.isGetter) { |
301 } | 635 if (treatPropertyAsField(declaration)) { |
302 return completions.toList(growable: false); | 636 try { |
303 } | 637 property.value = objectMirror.getField(symbol).reflectee; |
304 | 638 } catch (e) { |
305 /** | 639 property |
640 ..wasThrown = true | |
641 ..value = e; | |
642 } | |
643 } else if (accessorPropertiesOnly) { | |
644 property.getter = new _GetterTrampoline(objectMirror, | |
645 declaration, symbol); | |
646 } | |
647 } else if (declaration.isSetter) { | |
648 property.writable = true; | |
649 if (accessorPropertiesOnly && !treatPropertyAsField(declaration)) { | |
650 property.setter = new _SetterTrampoline(objectMirror, | |
651 declaration, MirrorSystem.getSymbol(name, libraryMirror)); | |
652 } | |
653 } | |
654 }); | |
655 } | |
656 | |
657 /** | |
658 * Flatten down the properties data structure into a List that is easy to | |
659 * access from native code. | |
660 */ | |
661 static List packageProperties(Map<String, _Property> properties) { | |
662 var ret = []; | |
663 for (var property in properties.values) { | |
664 ret.addAll([property.name, | |
665 property.setter, | |
666 property.getter, | |
667 property.value, | |
668 property.hasValue, | |
669 property.writable, | |
670 property.isMethod, | |
671 property.isOwn, | |
672 property.wasThrown]); | |
673 } | |
674 return ret; | |
675 } | |
676 | |
677 /** | |
678 * Get a property, returning null if the property does not exist. | |
679 * For private property names, we attempt to resolve the property in the | |
680 * context of each library that the property name could be associated with. | |
681 */ | |
682 static getObjectPropertySafe(o, String propertyName) { | |
683 var objectMirror = reflect(o); | |
684 var classMirror = objectMirror.type; | |
685 if (propertyName.startsWith("_")) { | |
686 var attemptedLibraries = new Set<LibraryMirror>(); | |
687 while (classMirror != null) { | |
688 LibraryMirror library = classMirror.owner; | |
689 if (!attemptedLibraries.contains(library)) { | |
690 try { | |
691 return objectMirror.getField( | |
692 MirrorSystem.getSymbol(propertyName, library)).reflectee; | |
693 } catch (e) { } | |
694 attemptedLibraries.add(library); | |
695 } | |
696 classMirror = classMirror.superclass; | |
697 } | |
698 return null; | |
699 } | |
700 try { | |
701 return objectMirror.getField( | |
702 MirrorSystem.getSymbol(propertyName)).reflectee; | |
703 } catch (e) { | |
704 return null; | |
705 } | |
706 } | |
707 | |
708 /** | |
306 * Convenience helper to get the keys of a [Map] as a [List]. | 709 * Convenience helper to get the keys of a [Map] as a [List]. |
307 */ | 710 */ |
308 static List getMapKeyList(Map map) => map.keys.toList(); | 711 static List getMapKeyList(Map map) => map.keys.toList(); |
309 | 712 |
310 /** | 713 /** |
311 * Returns the keys of an arbitrary Dart Map encoded as unique Strings. | 714 * Returns the keys of an arbitrary Dart Map encoded as unique Strings. |
312 * Keys that are strings are left unchanged except that the prefix ":" is | 715 * Keys that are strings are left unchanged except that the prefix ":" is |
313 * added to disambiguate keys from other Dart members. | 716 * added to disambiguate keys from other Dart members. |
314 * Keys that are not strings have # followed by the index of the key in the ma p | 717 * Keys that are not strings have # followed by the index of the key in the ma p |
315 * prepended to disambuguate. This scheme is simplistic but easy to encode and | 718 * prepended to disambuguate. This scheme is simplistic but easy to encode and |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
596 _scheduleImmediateHelper._schedule(callback); | 999 _scheduleImmediateHelper._schedule(callback); |
597 }; | 1000 }; |
598 | 1001 |
599 get _pureIsolateScheduleImmediateClosure => ((void callback()) => | 1002 get _pureIsolateScheduleImmediateClosure => ((void callback()) => |
600 throw new UnimplementedError("scheduleMicrotask in background isolates " | 1003 throw new UnimplementedError("scheduleMicrotask in background isolates " |
601 "are not supported in the browser")); | 1004 "are not supported in the browser")); |
602 | 1005 |
603 void _initializeCustomElement(Element e) { | 1006 void _initializeCustomElement(Element e) { |
604 _Utils.initializeCustomElement(e); | 1007 _Utils.initializeCustomElement(e); |
605 } | 1008 } |
OLD | NEW |