OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 trydart.poi; | 5 library trydart.poi; |
6 | 6 |
7 import 'dart:async' show | 7 import 'dart:async' show |
8 Completer, | 8 Completer, |
9 Future, | 9 Future, |
10 Stream; | 10 Stream; |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 | 307 |
308 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true; | 308 bool checkNoEnqueuedInvokedInstanceMethods(Enqueuer enqueuer) => true; |
309 | 309 |
310 void processWorkItem(void f(WorkItem work), WorkItem work) { | 310 void processWorkItem(void f(WorkItem work), WorkItem work) { |
311 if (work.element.library.canonicalUri == script) { | 311 if (work.element.library.canonicalUri == script) { |
312 f(work); | 312 f(work); |
313 } | 313 } |
314 } | 314 } |
315 } | 315 } |
316 | 316 |
| 317 /** |
| 318 * Serializes scope information about an element. This is accomplished by |
| 319 * calling the [serialize] method on each element. Some elements need special |
| 320 * treatment, as their enclosing scope must also be serialized. |
| 321 */ |
317 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { | 322 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
318 // TODO(ahe): Include function parameters and local variables. | 323 // TODO(ahe): Include function parameters and local variables. |
319 | 324 |
320 final Element element; | 325 final Element currentElement; |
321 final int position; | 326 final int position; |
322 final StringBuffer buffer = new StringBuffer(); | 327 final StringBuffer buffer = new StringBuffer(); |
323 int indentationLevel = 0; | 328 int indentationLevel = 0; |
| 329 ClassElement currentClass; |
324 | 330 |
325 ScopeInformationVisitor(this.element, this.position); | 331 ScopeInformationVisitor(this.currentElement, this.position); |
326 | 332 |
327 String get indentation => ' ' * indentationLevel; | 333 String get indentation => ' ' * indentationLevel; |
328 | 334 |
329 StringBuffer get indented => buffer..write(indentation); | 335 StringBuffer get indented => buffer..write(indentation); |
330 | 336 |
331 void visitElement(Element e) { | 337 void visitElement(Element e) { |
332 serialize(e, omitEnclosing: false); | 338 serialize(e, omitEnclosing: false); |
333 } | 339 } |
334 | 340 |
335 void visitLibraryElement(LibraryElement e) { | 341 void visitLibraryElement(LibraryElement e) { |
336 bool isFirst = true; | 342 bool isFirst = true; |
| 343 forEach(Element member) { |
| 344 if (!isFirst) { |
| 345 buffer.write(','); |
| 346 } |
| 347 buffer.write('\n'); |
| 348 indented; |
| 349 serialize(member); |
| 350 isFirst = false; |
| 351 } |
337 serialize( | 352 serialize( |
338 e, omitEnclosing: true, | 353 e, |
| 354 // TODO(ahe): We omit the import scope if there is no current |
| 355 // class. That's wrong. |
| 356 omitEnclosing: currentClass == null, |
339 name: e.getLibraryName(), | 357 name: e.getLibraryName(), |
| 358 serializeEnclosing: () { |
| 359 // The enclosing scope of a library is a scope which contains all the |
| 360 // imported names. |
| 361 isFirst = true; |
| 362 buffer.write('{\n'); |
| 363 indentationLevel++; |
| 364 indented.write('"kind": "imports",\n'); |
| 365 indented.write('"members": ['); |
| 366 indentationLevel++; |
| 367 e.importScope.importScope.values.forEach(forEach); |
| 368 indentationLevel--; |
| 369 buffer.write('\n'); |
| 370 indented.write('],\n'); |
| 371 // The enclosing scope of the imported names scope is the superclass |
| 372 // scope of the current class. |
| 373 indented.write('"enclosing": '); |
| 374 serializeClassSide( |
| 375 currentClass.superclass, isStatic: false, includeSuper: true); |
| 376 buffer.write('\n'); |
| 377 indentationLevel--; |
| 378 indented.write('}'); |
| 379 }, |
340 serializeMembers: () { | 380 serializeMembers: () { |
341 // TODO(ahe): Include imported elements in libraries. | 381 isFirst = true; |
342 e.forEachLocalMember((Element member) { | 382 e.localScope.values.forEach(forEach); |
343 if (!isFirst) { | |
344 buffer.write(','); | |
345 } | |
346 buffer.write('\n'); | |
347 indented; | |
348 serialize(member); | |
349 isFirst = false; | |
350 }); | |
351 }); | 383 }); |
352 } | 384 } |
353 | 385 |
| 386 void visitClassElement(ClassElement e) { |
| 387 currentClass = e; |
| 388 serializeClassSide(e, isStatic: true); |
| 389 } |
| 390 |
| 391 /// Serializes one of the "sides" a class. The sides of a class are "instance |
| 392 /// side" and "class side". These terms are from Smalltalk. The instance side |
| 393 /// is all the local instance members of the class (the members of the |
| 394 /// mixin), and the class side is the equivalent for static members and |
| 395 /// constructors. |
| 396 /// The scope chain is ordered so that the "class side" is searched before |
| 397 /// the "instance side". |
| 398 void serializeClassSide( |
| 399 ClassElement e, |
| 400 {bool isStatic: false, |
| 401 bool omitEnclosing: false, |
| 402 bool includeSuper: false}) { |
| 403 bool isFirst = true; |
| 404 String name = e.name; |
| 405 var serializeEnclosing; |
| 406 if (isStatic) { |
| 407 serializeEnclosing = () { |
| 408 serializeClassSide(e, isStatic: false, omitEnclosing: omitEnclosing); |
| 409 }; |
| 410 } else { |
| 411 name = "this($name)"; |
| 412 } |
| 413 if (includeSuper) { |
| 414 assert(!omitEnclosing && !isStatic); |
| 415 if (e.superclass == null) { |
| 416 omitEnclosing = true; |
| 417 } else { |
| 418 // Members of the superclass are represented as a separate scope. |
| 419 serializeEnclosing = () { |
| 420 serializeClassSide( |
| 421 e.superclass, isStatic: false, omitEnclosing: false, |
| 422 includeSuper: true); |
| 423 }; |
| 424 } |
| 425 } |
| 426 serialize( |
| 427 e, omitEnclosing: omitEnclosing, serializeEnclosing: serializeEnclosing, |
| 428 name: name, serializeMembers: () { |
| 429 e.forEachLocalMember((Element member) { |
| 430 // Filter out members that don't belong to this "side". |
| 431 if (member.isStatic != isStatic) return; |
| 432 if (!isFirst) { |
| 433 buffer.write(','); |
| 434 } |
| 435 buffer.write('\n'); |
| 436 indented; |
| 437 serialize(member); |
| 438 isFirst = false; |
| 439 }); |
| 440 }); |
| 441 } |
| 442 |
354 void visitScopeContainerElement(ScopeContainerElement e) { | 443 void visitScopeContainerElement(ScopeContainerElement e) { |
355 bool isFirst = true; | 444 bool isFirst = true; |
356 serialize(e, omitEnclosing: false, serializeMembers: () { | 445 serialize(e, omitEnclosing: false, serializeMembers: () { |
357 // TODO(ahe): Include inherited members in classes. | |
358 e.forEachLocalMember((Element member) { | 446 e.forEachLocalMember((Element member) { |
359 if (!isFirst) { | 447 if (!isFirst) { |
360 buffer.write(','); | 448 buffer.write(','); |
361 } | 449 } |
362 buffer.write('\n'); | 450 buffer.write('\n'); |
363 indented; | 451 indented; |
364 serialize(member); | 452 serialize(member); |
365 isFirst = false; | 453 isFirst = false; |
366 }); | 454 }); |
367 }); | 455 }); |
368 } | 456 } |
369 | 457 |
370 void visitCompilationUnitElement(CompilationUnitElement e) { | 458 void visitCompilationUnitElement(CompilationUnitElement e) { |
371 e.enclosingElement.accept(this); | 459 e.enclosingElement.accept(this); |
372 } | 460 } |
373 | 461 |
374 void serialize( | 462 void serialize( |
375 Element element, | 463 Element element, |
376 {bool omitEnclosing: true, | 464 {bool omitEnclosing: true, |
377 void serializeMembers(), | 465 void serializeMembers(), |
| 466 void serializeEnclosing(), |
378 String name}) { | 467 String name}) { |
379 DartType type; | 468 DartType type; |
380 int category = element.kind.category; | 469 int category = element.kind.category; |
381 if (category == ElementCategory.FUNCTION || | 470 if (category == ElementCategory.FUNCTION || |
382 category == ElementCategory.VARIABLE || | 471 category == ElementCategory.VARIABLE || |
383 element.isConstructor) { | 472 element.isConstructor) { |
384 type = element.computeType(cachedCompiler); | 473 type = element.computeType(cachedCompiler); |
385 } | 474 } |
386 if (name == null) { | 475 if (name == null) { |
387 name = element.name; | 476 name = element.name; |
388 } | 477 } |
389 buffer.write('{\n'); | 478 buffer.write('{\n'); |
390 indentationLevel++; | 479 indentationLevel++; |
391 indented | 480 if (name != '') { |
392 ..write('"name": "') | 481 indented |
393 ..write(name) | 482 ..write('"name": "') |
394 ..write('",\n'); | 483 ..write(name) |
| 484 ..write('",\n'); |
| 485 } |
395 indented | 486 indented |
396 ..write('"kind": "') | 487 ..write('"kind": "') |
397 ..write(element.kind) | 488 ..write(element.kind) |
398 ..write('"'); | 489 ..write('"'); |
399 if (type != null) { | 490 if (type != null) { |
400 buffer.write(',\n'); | 491 buffer.write(',\n'); |
401 indented | 492 indented |
402 ..write('"type": "') | 493 ..write('"type": "') |
403 ..write(type) | 494 ..write(type) |
404 ..write('"'); | 495 ..write('"'); |
405 } | 496 } |
406 if (serializeMembers != null) { | 497 if (serializeMembers != null) { |
407 buffer.write(',\n'); | 498 buffer.write(',\n'); |
408 indented.write('"members": ['); | 499 indented.write('"members": ['); |
409 indentationLevel++; | 500 indentationLevel++; |
410 serializeMembers(); | 501 serializeMembers(); |
411 indentationLevel--; | 502 indentationLevel--; |
412 buffer.write('\n'); | 503 buffer.write('\n'); |
413 indented.write(']'); | 504 indented.write(']'); |
414 } | 505 } |
415 if (!omitEnclosing) { | 506 if (!omitEnclosing) { |
416 buffer.write(',\n'); | 507 buffer.write(',\n'); |
417 indented.write('"enclosing": '); | 508 indented.write('"enclosing": '); |
418 element.enclosingElement.accept(this); | 509 if (serializeEnclosing != null) { |
| 510 serializeEnclosing(); |
| 511 } else { |
| 512 element.enclosingElement.accept(this); |
| 513 } |
419 } | 514 } |
420 indentationLevel--; | 515 indentationLevel--; |
421 buffer.write('\n'); | 516 buffer.write('\n'); |
422 indented.write('}'); | 517 indented.write('}'); |
423 } | 518 } |
424 } | 519 } |
OLD | NEW |