OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.mirrors_used; | 5 library dart2js.mirrors_used; |
6 | 6 |
7 import 'common/tasks.dart' show | 7 import 'common/tasks.dart' show |
8 CompilerTask; | 8 CompilerTask; |
9 import 'compile_time_constants.dart' show | 9 import 'compile_time_constants.dart' show |
10 ConstantCompiler; | 10 ConstantCompiler; |
11 import 'compiler.dart' show | 11 import 'compiler.dart' show |
12 Compiler; | 12 Compiler; |
13 import 'constants/expressions.dart'; | 13 import 'constants/expressions.dart'; |
14 import 'constants/values.dart' show | 14 import 'constants/values.dart' show |
15 ConstantValue, | 15 ConstantValue, |
16 ConstructedConstantValue, | 16 ConstructedConstantValue, |
17 ListConstantValue, | 17 ListConstantValue, |
18 StringConstantValue, | 18 StringConstantValue, |
19 TypeConstantValue; | 19 TypeConstantValue; |
20 import 'dart_types.dart' show | 20 import 'dart_types.dart' show |
21 DartType, | 21 DartType, |
22 InterfaceType, | 22 InterfaceType, |
23 TypeKind; | 23 TypeKind; |
| 24 import 'diagnostics/diagnostic_listener.dart' show |
| 25 DiagnosticReporter; |
24 import 'diagnostics/messages.dart' show | 26 import 'diagnostics/messages.dart' show |
25 MessageKind; | 27 MessageKind; |
26 import 'diagnostics/spannable.dart' show | 28 import 'diagnostics/spannable.dart' show |
27 Spannable; | 29 Spannable; |
28 import 'elements/elements.dart' show | 30 import 'elements/elements.dart' show |
29 ClassElement, | 31 ClassElement, |
30 Element, | 32 Element, |
31 ImportElement, | 33 ImportElement, |
32 LibraryElement, | 34 LibraryElement, |
33 MetadataAnnotation, | 35 MetadataAnnotation, |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 final Map<ConstantValue, List<String>> cachedStrings; | 169 final Map<ConstantValue, List<String>> cachedStrings; |
168 final Map<ConstantValue, List<Element>> cachedElements; | 170 final Map<ConstantValue, List<Element>> cachedElements; |
169 MirrorUsage mergedMirrorUsage; | 171 MirrorUsage mergedMirrorUsage; |
170 | 172 |
171 MirrorUsageAnalyzer(Compiler compiler, this.task) | 173 MirrorUsageAnalyzer(Compiler compiler, this.task) |
172 : compiler = compiler, | 174 : compiler = compiler, |
173 librariesWithUsage = new Set<LibraryElement>(), | 175 librariesWithUsage = new Set<LibraryElement>(), |
174 cachedStrings = new Map<ConstantValue, List<String>>(), | 176 cachedStrings = new Map<ConstantValue, List<String>>(), |
175 cachedElements = new Map<ConstantValue, List<Element>>(); | 177 cachedElements = new Map<ConstantValue, List<Element>>(); |
176 | 178 |
| 179 DiagnosticReporter get reporter => compiler.reporter; |
| 180 |
177 /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also | 181 /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also |
178 /// compute which libraries have the annotation (which is used by | 182 /// compute which libraries have the annotation (which is used by |
179 /// [MirrorUsageAnalyzerTask.hasMirrorUsage]). | 183 /// [MirrorUsageAnalyzerTask.hasMirrorUsage]). |
180 void run() { | 184 void run() { |
181 wildcard = compiler.libraryLoader.libraries.toList(); | 185 wildcard = compiler.libraryLoader.libraries.toList(); |
182 Map<LibraryElement, List<MirrorUsage>> usageMap = | 186 Map<LibraryElement, List<MirrorUsage>> usageMap = |
183 collectMirrorsUsedAnnotation(); | 187 collectMirrorsUsedAnnotation(); |
184 propagateOverrides(usageMap); | 188 propagateOverrides(usageMap); |
185 Set<LibraryElement> librariesWithoutUsage = new Set<LibraryElement>(); | 189 Set<LibraryElement> librariesWithoutUsage = new Set<LibraryElement>(); |
186 usageMap.forEach((LibraryElement library, List<MirrorUsage> usage) { | 190 usageMap.forEach((LibraryElement library, List<MirrorUsage> usage) { |
187 if (usage.isEmpty) librariesWithoutUsage.add(library); | 191 if (usage.isEmpty) librariesWithoutUsage.add(library); |
188 }); | 192 }); |
189 if (librariesWithoutUsage.isEmpty) { | 193 if (librariesWithoutUsage.isEmpty) { |
190 mergedMirrorUsage = mergeUsages(usageMap); | 194 mergedMirrorUsage = mergeUsages(usageMap); |
191 } else { | 195 } else { |
192 mergedMirrorUsage = new MirrorUsage(null, null, null, null); | 196 mergedMirrorUsage = new MirrorUsage(null, null, null, null); |
193 } | 197 } |
194 } | 198 } |
195 | 199 |
196 /// Collect all @MirrorsUsed from all libraries and represent them as | 200 /// Collect all @MirrorsUsed from all libraries and represent them as |
197 /// [MirrorUsage]. | 201 /// [MirrorUsage]. |
198 Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() { | 202 Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() { |
199 Map<LibraryElement, List<MirrorUsage>> result = | 203 Map<LibraryElement, List<MirrorUsage>> result = |
200 new Map<LibraryElement, List<MirrorUsage>>(); | 204 new Map<LibraryElement, List<MirrorUsage>>(); |
201 for (LibraryElement library in compiler.libraryLoader.libraries) { | 205 for (LibraryElement library in compiler.libraryLoader.libraries) { |
202 if (library.isInternalLibrary) continue; | 206 if (library.isInternalLibrary) continue; |
203 for (ImportElement import in library.imports) { | 207 for (ImportElement import in library.imports) { |
204 compiler.withCurrentElement(library, () { | 208 reporter.withCurrentElement(library, () { |
205 List<MirrorUsage> usages = | 209 List<MirrorUsage> usages = |
206 mirrorsUsedOnLibraryTag(library, import); | 210 mirrorsUsedOnLibraryTag(library, import); |
207 if (usages != null) { | 211 if (usages != null) { |
208 List<MirrorUsage> existing = result[library]; | 212 List<MirrorUsage> existing = result[library]; |
209 if (existing != null) { | 213 if (existing != null) { |
210 existing.addAll(usages); | 214 existing.addAll(usages); |
211 } else { | 215 } else { |
212 result[library] = usages; | 216 result[library] = usages; |
213 } | 217 } |
214 } | 218 } |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 | 379 |
376 MirrorUsageBuilder( | 380 MirrorUsageBuilder( |
377 this.analyzer, | 381 this.analyzer, |
378 this.enclosingLibrary, | 382 this.enclosingLibrary, |
379 this.spannable, | 383 this.spannable, |
380 this.constant, | 384 this.constant, |
381 this.elements); | 385 this.elements); |
382 | 386 |
383 Compiler get compiler => analyzer.compiler; | 387 Compiler get compiler => analyzer.compiler; |
384 | 388 |
| 389 DiagnosticReporter get reporter => analyzer.reporter; |
| 390 |
385 /// Convert a constant to a list of [String] and [Type] values. If the | 391 /// Convert a constant to a list of [String] and [Type] values. If the |
386 /// constant is a single [String], it is assumed to be a comma-separated list | 392 /// constant is a single [String], it is assumed to be a comma-separated list |
387 /// of qualified names. If the constant is a [Type] t, the result is [:[t]:]. | 393 /// of qualified names. If the constant is a [Type] t, the result is [:[t]:]. |
388 /// Otherwise, the constant is assumed to represent a list of strings (each a | 394 /// Otherwise, the constant is assumed to represent a list of strings (each a |
389 /// qualified name) and types, and such a list is constructed. If | 395 /// qualified name) and types, and such a list is constructed. If |
390 /// [onlyStrings] is true, the returned list is a [:List<String>:] and any | 396 /// [onlyStrings] is true, the returned list is a [:List<String>:] and any |
391 /// [Type] values are treated as an error (meaning that the value is ignored | 397 /// [Type] values are treated as an error (meaning that the value is ignored |
392 /// and a hint is emitted). | 398 /// and a hint is emitted). |
393 List convertConstantToUsageList( | 399 List convertConstantToUsageList( |
394 ConstantValue constant, { bool onlyStrings: false }) { | 400 ConstantValue constant, { bool onlyStrings: false }) { |
395 if (constant.isNull) { | 401 if (constant.isNull) { |
396 return null; | 402 return null; |
397 } else if (constant.isList) { | 403 } else if (constant.isList) { |
398 ListConstantValue list = constant; | 404 ListConstantValue list = constant; |
399 List result = onlyStrings ? <String> [] : []; | 405 List result = onlyStrings ? <String> [] : []; |
400 for (ConstantValue entry in list.entries) { | 406 for (ConstantValue entry in list.entries) { |
401 if (entry.isString) { | 407 if (entry.isString) { |
402 StringConstantValue string = entry; | 408 StringConstantValue string = entry; |
403 result.add(string.primitiveValue.slowToString()); | 409 result.add(string.primitiveValue.slowToString()); |
404 } else if (!onlyStrings && entry.isType) { | 410 } else if (!onlyStrings && entry.isType) { |
405 TypeConstantValue type = entry; | 411 TypeConstantValue type = entry; |
406 result.add(type.representedType); | 412 result.add(type.representedType); |
407 } else { | 413 } else { |
408 Spannable node = positionOf(entry); | 414 Spannable node = positionOf(entry); |
409 MessageKind kind = onlyStrings | 415 MessageKind kind = onlyStrings |
410 ? MessageKind.MIRRORS_EXPECTED_STRING | 416 ? MessageKind.MIRRORS_EXPECTED_STRING |
411 : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE; | 417 : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE; |
412 compiler.reportHintMessage( | 418 reporter.reportHintMessage( |
413 node, kind, {'name': node, 'type': apiTypeOf(entry)}); | 419 node, kind, {'name': node, 'type': apiTypeOf(entry)}); |
414 } | 420 } |
415 } | 421 } |
416 return result; | 422 return result; |
417 } else if (!onlyStrings && constant.isType) { | 423 } else if (!onlyStrings && constant.isType) { |
418 TypeConstantValue type = constant; | 424 TypeConstantValue type = constant; |
419 return [type.representedType]; | 425 return [type.representedType]; |
420 } else if (constant.isString) { | 426 } else if (constant.isString) { |
421 StringConstantValue string = constant; | 427 StringConstantValue string = constant; |
422 var iterable = | 428 var iterable = |
423 string.primitiveValue.slowToString().split(',').map((e) => e.trim()); | 429 string.primitiveValue.slowToString().split(',').map((e) => e.trim()); |
424 return onlyStrings ? new List<String>.from(iterable) : iterable.toList(); | 430 return onlyStrings ? new List<String>.from(iterable) : iterable.toList(); |
425 } else { | 431 } else { |
426 Spannable node = positionOf(constant); | 432 Spannable node = positionOf(constant); |
427 MessageKind kind = onlyStrings | 433 MessageKind kind = onlyStrings |
428 ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST | 434 ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST |
429 : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST; | 435 : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST; |
430 compiler.reportHintMessage( | 436 reporter.reportHintMessage( |
431 node, kind, {'name': node, 'type': apiTypeOf(constant)}); | 437 node, kind, {'name': node, 'type': apiTypeOf(constant)}); |
432 return null; | 438 return null; |
433 } | 439 } |
434 } | 440 } |
435 | 441 |
436 /// Find the first non-implementation interface of constant. | 442 /// Find the first non-implementation interface of constant. |
437 DartType apiTypeOf(ConstantValue constant) { | 443 DartType apiTypeOf(ConstantValue constant) { |
438 DartType type = constant.getType(compiler.coreTypes); | 444 DartType type = constant.getType(compiler.coreTypes); |
439 LibraryElement library = type.element.library; | 445 LibraryElement library = type.element.library; |
440 if (type.isInterfaceType && library.isInternalLibrary) { | 446 if (type.isInterfaceType && library.isInternalLibrary) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
504 } | 510 } |
505 } | 511 } |
506 return result; | 512 return result; |
507 } | 513 } |
508 | 514 |
509 /// Resolve [expression] in [enclosingLibrary]'s import scope. | 515 /// Resolve [expression] in [enclosingLibrary]'s import scope. |
510 Element resolveExpression(String expression) { | 516 Element resolveExpression(String expression) { |
511 List<String> identifiers = expression.split('.'); | 517 List<String> identifiers = expression.split('.'); |
512 Element element = enclosingLibrary.find(identifiers[0]); | 518 Element element = enclosingLibrary.find(identifiers[0]); |
513 if (element == null) { | 519 if (element == null) { |
514 compiler.reportHintMessage( | 520 reporter.reportHintMessage( |
515 spannable, | 521 spannable, |
516 MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY, | 522 MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY, |
517 {'name': expression}); | 523 {'name': expression}); |
518 return null; | 524 return null; |
519 } else { | 525 } else { |
520 if (identifiers.length == 1) return element; | 526 if (identifiers.length == 1) return element; |
521 return resolveLocalExpression(element, identifiers.sublist(1)); | 527 return resolveLocalExpression(element, identifiers.sublist(1)); |
522 } | 528 } |
523 } | 529 } |
524 | 530 |
525 /// Resolve [identifiers] in [element]'s local members. | 531 /// Resolve [identifiers] in [element]'s local members. |
526 Element resolveLocalExpression(Element element, List<String> identifiers) { | 532 Element resolveLocalExpression(Element element, List<String> identifiers) { |
527 Element current = element; | 533 Element current = element; |
528 for (String identifier in identifiers) { | 534 for (String identifier in identifiers) { |
529 Element e = findLocalMemberIn(current, identifier); | 535 Element e = findLocalMemberIn(current, identifier); |
530 if (e == null) { | 536 if (e == null) { |
531 if (current.isLibrary) { | 537 if (current.isLibrary) { |
532 LibraryElement library = current; | 538 LibraryElement library = current; |
533 compiler.reportHintMessage( | 539 reporter.reportHintMessage( |
534 spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY, | 540 spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY, |
535 {'name': identifiers[0], | 541 {'name': identifiers[0], |
536 'library': library.libraryOrScriptName}); | 542 'library': library.libraryOrScriptName}); |
537 } else { | 543 } else { |
538 compiler.reportHintMessage( | 544 reporter.reportHintMessage( |
539 spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT, | 545 spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT, |
540 {'name': identifier, 'element': current.name}); | 546 {'name': identifier, 'element': current.name}); |
541 } | 547 } |
542 return current; | 548 return current; |
543 } | 549 } |
544 current = e; | 550 current = e; |
545 } | 551 } |
546 return current; | 552 return current; |
547 } | 553 } |
548 | 554 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 // @MirrorsUsed(targets: fisk) | 590 // @MirrorsUsed(targets: fisk) |
585 // ^^^^ | 591 // ^^^^ |
586 // | 592 // |
587 // Instead of saying 'fisk' should pretty print the problematic constant | 593 // Instead of saying 'fisk' should pretty print the problematic constant |
588 // value. | 594 // value. |
589 return spannable; | 595 return spannable; |
590 } | 596 } |
591 return node; | 597 return node; |
592 } | 598 } |
593 } | 599 } |
OLD | NEW |