| 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 |