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 'constants/expressions.dart'; | 7 import 'constants/expressions.dart'; |
8 import 'constants/values.dart' show | 8 import 'constants/values.dart' show |
9 Constant, | 9 ConstantValue, |
10 ConstructedConstant, | 10 ConstructedConstantValue, |
11 ListConstant, | 11 ListConstantValue, |
12 StringConstant, | 12 StringConstantValue, |
13 TypeConstant; | 13 TypeConstantValue; |
14 | 14 |
15 import 'dart_types.dart' show | 15 import 'dart_types.dart' show |
16 DartType, | 16 DartType, |
17 InterfaceType, | 17 InterfaceType, |
18 TypeKind; | 18 TypeKind; |
19 | 19 |
20 import 'dart2jslib.dart' show | 20 import 'dart2jslib.dart' show |
21 Compiler, | 21 Compiler, |
22 CompilerTask, | 22 CompilerTask, |
23 ConstantCompiler, | 23 ConstantCompiler, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 } | 128 } |
129 | 129 |
130 /// Call-back from the resolver to analyze MirorsUsed annotations. The result | 130 /// Call-back from the resolver to analyze MirorsUsed annotations. The result |
131 /// is stored in [analyzer] and later used to compute | 131 /// is stored in [analyzer] and later used to compute |
132 /// [:analyzer.mergedMirrorUsage:]. | 132 /// [:analyzer.mergedMirrorUsage:]. |
133 void validate(NewExpression node, TreeElements mapping) { | 133 void validate(NewExpression node, TreeElements mapping) { |
134 for (Node argument in node.send.arguments) { | 134 for (Node argument in node.send.arguments) { |
135 NamedArgument named = argument.asNamedArgument(); | 135 NamedArgument named = argument.asNamedArgument(); |
136 if (named == null) continue; | 136 if (named == null) continue; |
137 ConstantCompiler constantCompiler = compiler.resolver.constantCompiler; | 137 ConstantCompiler constantCompiler = compiler.resolver.constantCompiler; |
138 Constant value = | 138 ConstantValue value = |
139 constantCompiler.compileNode(named.expression, mapping).value; | 139 constantCompiler.compileNode(named.expression, mapping).value; |
140 | 140 |
141 MirrorUsageBuilder builder = | 141 MirrorUsageBuilder builder = |
142 new MirrorUsageBuilder( | 142 new MirrorUsageBuilder( |
143 analyzer, mapping.analyzedElement.library, named.expression, | 143 analyzer, mapping.analyzedElement.library, named.expression, |
144 value, mapping); | 144 value, mapping); |
145 | 145 |
146 if (named.name.source == 'symbols') { | 146 if (named.name.source == 'symbols') { |
147 analyzer.cachedStrings[value] = | 147 analyzer.cachedStrings[value] = |
148 builder.convertConstantToUsageList(value, onlyStrings: true); | 148 builder.convertConstantToUsageList(value, onlyStrings: true); |
149 } else if (named.name.source == 'targets') { | 149 } else if (named.name.source == 'targets') { |
150 analyzer.cachedElements[value] = | 150 analyzer.cachedElements[value] = |
151 builder.resolveUsageList(builder.convertConstantToUsageList(value)); | 151 builder.resolveUsageList(builder.convertConstantToUsageList(value)); |
152 } else if (named.name.source == 'metaTargets') { | 152 } else if (named.name.source == 'metaTargets') { |
153 analyzer.cachedElements[value] = | 153 analyzer.cachedElements[value] = |
154 builder.resolveUsageList(builder.convertConstantToUsageList(value)); | 154 builder.resolveUsageList(builder.convertConstantToUsageList(value)); |
155 } else if (named.name.source == 'override') { | 155 } else if (named.name.source == 'override') { |
156 analyzer.cachedElements[value] = | 156 analyzer.cachedElements[value] = |
157 builder.resolveUsageList(builder.convertConstantToUsageList(value)); | 157 builder.resolveUsageList(builder.convertConstantToUsageList(value)); |
158 } | 158 } |
159 } | 159 } |
160 } | 160 } |
161 } | 161 } |
162 | 162 |
163 class MirrorUsageAnalyzer { | 163 class MirrorUsageAnalyzer { |
164 final Compiler compiler; | 164 final Compiler compiler; |
165 final MirrorUsageAnalyzerTask task; | 165 final MirrorUsageAnalyzerTask task; |
166 List<LibraryElement> wildcard; | 166 List<LibraryElement> wildcard; |
167 final Set<LibraryElement> librariesWithUsage; | 167 final Set<LibraryElement> librariesWithUsage; |
168 final Map<Constant, List<String>> cachedStrings; | 168 final Map<ConstantValue, List<String>> cachedStrings; |
169 final Map<Constant, List<Element>> cachedElements; | 169 final Map<ConstantValue, List<Element>> cachedElements; |
170 MirrorUsage mergedMirrorUsage; | 170 MirrorUsage mergedMirrorUsage; |
171 | 171 |
172 MirrorUsageAnalyzer(Compiler compiler, this.task) | 172 MirrorUsageAnalyzer(Compiler compiler, this.task) |
173 : compiler = compiler, | 173 : compiler = compiler, |
174 librariesWithUsage = new Set<LibraryElement>(), | 174 librariesWithUsage = new Set<LibraryElement>(), |
175 cachedStrings = new Map<Constant, List<String>>(), | 175 cachedStrings = new Map<ConstantValue, List<String>>(), |
176 cachedElements = new Map<Constant, List<Element>>(); | 176 cachedElements = new Map<ConstantValue, List<Element>>(); |
177 | 177 |
178 /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also | 178 /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also |
179 /// compute which libraries have the annotation (which is used by | 179 /// compute which libraries have the annotation (which is used by |
180 /// [MirrorUsageAnalyzerTask.hasMirrorUsage]). | 180 /// [MirrorUsageAnalyzerTask.hasMirrorUsage]). |
181 void run() { | 181 void run() { |
182 wildcard = compiler.libraryLoader.libraries.toList(); | 182 wildcard = compiler.libraryLoader.libraries.toList(); |
183 Map<LibraryElement, List<MirrorUsage>> usageMap = | 183 Map<LibraryElement, List<MirrorUsage>> usageMap = |
184 collectMirrorsUsedAnnotation(); | 184 collectMirrorsUsedAnnotation(); |
185 propagateOverrides(usageMap); | 185 propagateOverrides(usageMap); |
186 Set<LibraryElement> librariesWithoutUsage = new Set<LibraryElement>(); | 186 Set<LibraryElement> librariesWithoutUsage = new Set<LibraryElement>(); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 if (metaTargets == null) { | 319 if (metaTargets == null) { |
320 metaTargets = b.metaTargets; | 320 metaTargets = b.metaTargets; |
321 } else if (metaTargets != wildcard && b.metaTargets != null) { | 321 } else if (metaTargets != wildcard && b.metaTargets != null) { |
322 metaTargets.addAll(b.metaTargets); | 322 metaTargets.addAll(b.metaTargets); |
323 } | 323 } |
324 return new MirrorUsage(symbols, targets, metaTargets, null); | 324 return new MirrorUsage(symbols, targets, metaTargets, null); |
325 } | 325 } |
326 | 326 |
327 /// Convert a [constant] to an instance of [MirrorUsage] using information | 327 /// Convert a [constant] to an instance of [MirrorUsage] using information |
328 /// that was resolved during [MirrorUsageAnalyzerTask.validate]. | 328 /// that was resolved during [MirrorUsageAnalyzerTask.validate]. |
329 MirrorUsage buildUsage(ConstructedConstant constant) { | 329 MirrorUsage buildUsage(ConstructedConstantValue constant) { |
330 Map<Element, Constant> fields = constant.fieldElements; | 330 Map<Element, ConstantValue> fields = constant.fieldElements; |
331 VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember( | 331 VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember( |
332 'symbols'); | 332 'symbols'); |
333 VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember( | 333 VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember( |
334 'targets'); | 334 'targets'); |
335 VariableElement metaTargetsField = | 335 VariableElement metaTargetsField = |
336 compiler.mirrorsUsedClass.lookupLocalMember( | 336 compiler.mirrorsUsedClass.lookupLocalMember( |
337 'metaTargets'); | 337 'metaTargets'); |
338 VariableElement overrideField = compiler.mirrorsUsedClass.lookupLocalMember( | 338 VariableElement overrideField = compiler.mirrorsUsedClass.lookupLocalMember( |
339 'override'); | 339 'override'); |
340 | 340 |
(...skipping 23 matching lines...) Expand all Loading... |
364 'override = $override' | 364 'override = $override' |
365 ')'; | 365 ')'; |
366 | 366 |
367 } | 367 } |
368 } | 368 } |
369 | 369 |
370 class MirrorUsageBuilder { | 370 class MirrorUsageBuilder { |
371 final MirrorUsageAnalyzer analyzer; | 371 final MirrorUsageAnalyzer analyzer; |
372 final LibraryElement enclosingLibrary; | 372 final LibraryElement enclosingLibrary; |
373 final Spannable spannable; | 373 final Spannable spannable; |
374 final Constant constant; | 374 final ConstantValue constant; |
375 final TreeElements elements; | 375 final TreeElements elements; |
376 | 376 |
377 MirrorUsageBuilder( | 377 MirrorUsageBuilder( |
378 this.analyzer, | 378 this.analyzer, |
379 this.enclosingLibrary, | 379 this.enclosingLibrary, |
380 this.spannable, | 380 this.spannable, |
381 this.constant, | 381 this.constant, |
382 this.elements); | 382 this.elements); |
383 | 383 |
384 Compiler get compiler => analyzer.compiler; | 384 Compiler get compiler => analyzer.compiler; |
385 | 385 |
386 /// Convert a constant to a list of [String] and [Type] values. If the | 386 /// Convert a constant to a list of [String] and [Type] values. If the |
387 /// constant is a single [String], it is assumed to be a comma-separated list | 387 /// constant is a single [String], it is assumed to be a comma-separated list |
388 /// of qualified names. If the constant is a [Type] t, the result is [:[t]:]. | 388 /// of qualified names. If the constant is a [Type] t, the result is [:[t]:]. |
389 /// Otherwise, the constant is assumed to represent a list of strings (each a | 389 /// Otherwise, the constant is assumed to represent a list of strings (each a |
390 /// qualified name) and types, and such a list is constructed. If | 390 /// qualified name) and types, and such a list is constructed. If |
391 /// [onlyStrings] is true, the returned list is a [:List<String>:] and any | 391 /// [onlyStrings] is true, the returned list is a [:List<String>:] and any |
392 /// [Type] values are treated as an error (meaning that the value is ignored | 392 /// [Type] values are treated as an error (meaning that the value is ignored |
393 /// and a hint is emitted). | 393 /// and a hint is emitted). |
394 List convertConstantToUsageList( | 394 List convertConstantToUsageList( |
395 Constant constant, { bool onlyStrings: false }) { | 395 ConstantValue constant, { bool onlyStrings: false }) { |
396 if (constant.isNull) { | 396 if (constant.isNull) { |
397 return null; | 397 return null; |
398 } else if (constant.isList) { | 398 } else if (constant.isList) { |
399 ListConstant list = constant; | 399 ListConstantValue list = constant; |
400 List result = onlyStrings ? <String> [] : []; | 400 List result = onlyStrings ? <String> [] : []; |
401 for (Constant entry in list.entries) { | 401 for (ConstantValue entry in list.entries) { |
402 if (entry.isString) { | 402 if (entry.isString) { |
403 StringConstant string = entry; | 403 StringConstantValue string = entry; |
404 result.add(string.value.slowToString()); | 404 result.add(string.primitiveValue.slowToString()); |
405 } else if (!onlyStrings && entry.isType) { | 405 } else if (!onlyStrings && entry.isType) { |
406 TypeConstant type = entry; | 406 TypeConstantValue type = entry; |
407 result.add(type.representedType); | 407 result.add(type.representedType); |
408 } else { | 408 } else { |
409 Spannable node = positionOf(entry); | 409 Spannable node = positionOf(entry); |
410 MessageKind kind = onlyStrings | 410 MessageKind kind = onlyStrings |
411 ? MessageKind.MIRRORS_EXPECTED_STRING | 411 ? MessageKind.MIRRORS_EXPECTED_STRING |
412 : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE; | 412 : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE; |
413 compiler.reportHint( | 413 compiler.reportHint( |
414 node, | 414 node, |
415 kind, {'name': node, 'type': apiTypeOf(entry)}); | 415 kind, {'name': node, 'type': apiTypeOf(entry)}); |
416 } | 416 } |
417 } | 417 } |
418 return result; | 418 return result; |
419 } else if (!onlyStrings && constant.isType) { | 419 } else if (!onlyStrings && constant.isType) { |
420 TypeConstant type = constant; | 420 TypeConstantValue type = constant; |
421 return [type.representedType]; | 421 return [type.representedType]; |
422 } else if (constant.isString) { | 422 } else if (constant.isString) { |
423 StringConstant string = constant; | 423 StringConstantValue string = constant; |
424 var iterable = | 424 var iterable = |
425 string.value.slowToString().split(',').map((e) => e.trim()); | 425 string.primitiveValue.slowToString().split(',').map((e) => e.trim()); |
426 return onlyStrings ? new List<String>.from(iterable) : iterable.toList(); | 426 return onlyStrings ? new List<String>.from(iterable) : iterable.toList(); |
427 } else { | 427 } else { |
428 Spannable node = positionOf(constant); | 428 Spannable node = positionOf(constant); |
429 MessageKind kind = onlyStrings | 429 MessageKind kind = onlyStrings |
430 ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST | 430 ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST |
431 : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST; | 431 : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST; |
432 compiler.reportHint( | 432 compiler.reportHint( |
433 node, | 433 node, |
434 kind, {'name': node, 'type': apiTypeOf(constant)}); | 434 kind, {'name': node, 'type': apiTypeOf(constant)}); |
435 return null; | 435 return null; |
436 } | 436 } |
437 } | 437 } |
438 | 438 |
439 /// Find the first non-implementation interface of constant. | 439 /// Find the first non-implementation interface of constant. |
440 DartType apiTypeOf(Constant constant) { | 440 DartType apiTypeOf(ConstantValue constant) { |
441 DartType type = constant.computeType(compiler); | 441 DartType type = constant.computeType(compiler); |
442 LibraryElement library = type.element.library; | 442 LibraryElement library = type.element.library; |
443 if (type.isInterfaceType && library.isInternalLibrary) { | 443 if (type.isInterfaceType && library.isInternalLibrary) { |
444 InterfaceType interface = type; | 444 InterfaceType interface = type; |
445 ClassElement cls = type.element; | 445 ClassElement cls = type.element; |
446 cls.ensureResolved(compiler); | 446 cls.ensureResolved(compiler); |
447 for (DartType supertype in cls.allSupertypes) { | 447 for (DartType supertype in cls.allSupertypes) { |
448 if (supertype.isInterfaceType | 448 if (supertype.isInterfaceType |
449 && !supertype.element.library.isInternalLibrary) { | 449 && !supertype.element.library.isInternalLibrary) { |
450 return interface.asInstanceOf(supertype.element); | 450 return interface.asInstanceOf(supertype.element); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 if (element.isClass) { | 556 if (element.isClass) { |
557 ClassElement cls = element; | 557 ClassElement cls = element; |
558 cls.ensureResolved(compiler); | 558 cls.ensureResolved(compiler); |
559 } | 559 } |
560 return scope.localLookup(name); | 560 return scope.localLookup(name); |
561 } | 561 } |
562 return null; | 562 return null; |
563 } | 563 } |
564 | 564 |
565 /// Attempt to find a [Spannable] corresponding to constant. | 565 /// Attempt to find a [Spannable] corresponding to constant. |
566 Spannable positionOf(Constant constant) { | 566 Spannable positionOf(ConstantValue constant) { |
567 Node node; | 567 Node node; |
568 elements.forEachConstantNode((Node n, ConstExp c) { | 568 elements.forEachConstantNode((Node n, ConstantExpression c) { |
569 if (node == null && c.value == constant) { | 569 if (node == null && c.value == constant) { |
570 node = n; | 570 node = n; |
571 } | 571 } |
572 }); | 572 }); |
573 if (node == null) { | 573 if (node == null) { |
574 // TODO(ahe): Returning [spannable] here leads to confusing error | 574 // TODO(ahe): Returning [spannable] here leads to confusing error |
575 // messages. For example, consider: | 575 // messages. For example, consider: |
576 // @MirrorsUsed(targets: fisk) | 576 // @MirrorsUsed(targets: fisk) |
577 // import 'dart:mirrors'; | 577 // import 'dart:mirrors'; |
578 // | 578 // |
579 // const fisk = const [main]; | 579 // const fisk = const [main]; |
580 // | 580 // |
581 // main() {} | 581 // main() {} |
582 // | 582 // |
583 // The message is: | 583 // The message is: |
584 // example.dart:1:23: Hint: Can't use 'fisk' here because ... | 584 // example.dart:1:23: Hint: Can't use 'fisk' here because ... |
585 // Did you forget to add quotes? | 585 // Did you forget to add quotes? |
586 // @MirrorsUsed(targets: fisk) | 586 // @MirrorsUsed(targets: fisk) |
587 // ^^^^ | 587 // ^^^^ |
588 // | 588 // |
589 // Instead of saying 'fisk' should pretty print the problematic constant | 589 // Instead of saying 'fisk' should pretty print the problematic constant |
590 // value. | 590 // value. |
591 return spannable; | 591 return spannable; |
592 } | 592 } |
593 return node; | 593 return node; |
594 } | 594 } |
595 } | 595 } |
OLD | NEW |