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; |
Johnni Winther
2013/08/07 10:39:17
Overall for this file: Document methods.
ahe
2013/08/07 13:40:20
Done.
| |
6 | 6 |
7 import 'dart2jslib.dart' show | 7 import 'dart2jslib.dart' show |
8 Compiler, | 8 Compiler, |
9 CompilerTask, | 9 CompilerTask, |
10 Constant, | 10 Constant, |
11 ConstructedConstant, | 11 ConstructedConstant, |
12 ListConstant, | 12 ListConstant, |
13 MessageKind, | 13 MessageKind, |
14 SourceString, | 14 SourceString, |
15 StringConstant, | 15 StringConstant, |
16 TypeConstant; | 16 TreeElements, |
17 TypeConstant, | |
18 invariant; | |
17 | 19 |
18 import 'elements/elements.dart' show | 20 import 'elements/elements.dart' show |
21 ClassElement, | |
19 Element, | 22 Element, |
20 LibraryElement, | 23 LibraryElement, |
21 MetadataAnnotation, | 24 MetadataAnnotation, |
25 ScopeContainerElement, | |
22 VariableElement; | 26 VariableElement; |
23 | 27 |
24 import 'util/util.dart' show | 28 import 'util/util.dart' show |
25 Link; | 29 Link, |
30 Spannable; | |
26 | 31 |
27 import 'dart_types.dart' show | 32 import 'dart_types.dart' show |
28 DartType; | 33 DartType, |
34 InterfaceType, | |
35 TypeKind; | |
29 | 36 |
30 import 'tree/tree.dart' show | 37 import 'tree/tree.dart' show |
31 Import, | 38 Import, |
32 LibraryTag; | 39 LibraryTag, |
40 NamedArgument, | |
41 NewExpression, | |
42 Node; | |
43 | |
44 import 'resolution/resolution.dart' show | |
45 ConstantMapper; | |
33 | 46 |
34 /** | 47 /** |
35 * Compiler task that analyzes MirrorsUsed annotations. | 48 * Compiler task that analyzes MirrorsUsed annotations. |
36 * | 49 * |
37 * When importing 'dart:mirrors', it is possible to annotate the import with | 50 * When importing 'dart:mirrors', it is possible to annotate the import with |
38 * MirrorsUsed annotation. This is a way to declare what elements will be | 51 * MirrorsUsed annotation. This is a way to declare what elements will be |
39 * reflected on at runtime. Such elements, even they would normally be | 52 * reflected on at runtime. Such elements, even they would normally be |
40 * discarded by the implicit tree-shaking algorithm must be preserved in the | 53 * discarded by the implicit tree-shaking algorithm must be preserved in the |
41 * final output. | 54 * final output. |
42 * | 55 * |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 * | 87 * |
75 * On the other hand, if all libraries importing dart:mirrors have a | 88 * On the other hand, if all libraries importing dart:mirrors have a |
76 * MirrorsUsed annotation, these annotations are merged. | 89 * MirrorsUsed annotation, these annotations are merged. |
77 * | 90 * |
78 * MERGING MIRRORSUSED | 91 * MERGING MIRRORSUSED |
79 * | 92 * |
80 * TBD. | 93 * TBD. |
81 */ | 94 */ |
82 class MirrorUsageAnalyzerTask extends CompilerTask { | 95 class MirrorUsageAnalyzerTask extends CompilerTask { |
83 Set<LibraryElement> librariesWithUsage; | 96 Set<LibraryElement> librariesWithUsage; |
97 MirrorUsageAnalyzer analyzer; | |
84 | 98 |
85 MirrorUsageAnalyzerTask(Compiler compiler) | 99 MirrorUsageAnalyzerTask(Compiler compiler) |
86 : super(compiler); | 100 : super(compiler) { |
101 analyzer = new MirrorUsageAnalyzer(compiler, this); | |
102 } | |
87 | 103 |
88 void analyzeUsage(LibraryElement mainApp) { | 104 void analyzeUsage(LibraryElement mainApp) { |
89 if (compiler.mirrorsLibrary == null) return; | 105 if (compiler.mirrorsLibrary == null) return; |
90 MirrorUsageAnalyzer analyzer = new MirrorUsageAnalyzer(compiler, this); | |
91 measure(analyzer.run); | 106 measure(analyzer.run); |
92 List<String> symbols = analyzer.mergedMirrorUsage.symbols; | 107 List<String> symbols = analyzer.mergedMirrorUsage.symbols; |
93 List<Element> targets = analyzer.mergedMirrorUsage.targets; | 108 List<Element> targets = analyzer.mergedMirrorUsage.targets; |
94 List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets; | 109 List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets; |
95 compiler.backend.registerMirrorUsage( | 110 compiler.backend.registerMirrorUsage( |
96 symbols == null ? null : new Set<String>.from(symbols), | 111 symbols == null ? null : new Set<String>.from(symbols), |
97 targets == null ? null : new Set<Element>.from(targets), | 112 targets == null ? null : new Set<Element>.from(targets), |
98 metaTargets == null ? null : new Set<Element>.from(metaTargets)); | 113 metaTargets == null ? null : new Set<Element>.from(metaTargets)); |
99 librariesWithUsage = analyzer.librariesWithUsage; | 114 librariesWithUsage = analyzer.librariesWithUsage; |
100 } | 115 } |
101 | 116 |
102 bool hasMirrorUsage(Element element) { | 117 bool hasMirrorUsage(Element element) { |
103 return librariesWithUsage != null | 118 return librariesWithUsage != null |
104 && librariesWithUsage.contains(element.getLibrary()); | 119 && librariesWithUsage.contains(element.getLibrary()); |
105 } | 120 } |
121 | |
122 void validate(NewExpression node, TreeElements mapping) { | |
123 for (Node argument in node.send.arguments) { | |
124 NamedArgument named = argument.asNamedArgument(); | |
125 if (named == null) continue; | |
126 Constant value = compiler.metadataHandler.compileNodeWithDefinitions( | |
127 named.expression, mapping, isConst: true); | |
128 | |
129 ConstantMapper mapper = | |
130 new ConstantMapper(compiler.metadataHandler, mapping, compiler); | |
131 named.expression.accept(mapper); | |
132 | |
133 MirrorUsageBuilder builder = | |
134 new MirrorUsageBuilder( | |
135 analyzer, mapping.currentElement.getLibrary(), named.expression, | |
136 value, mapper.constantToNodeMap); | |
137 | |
138 if (named.name.source == const SourceString('symbols')) { | |
139 analyzer.cachedValues[value] = | |
140 builder.convertToListOfStrings( | |
141 builder.convertConstantToUsageList(value, onlyStrings: true)); | |
142 } else if (named.name.source == const SourceString('targets')) { | |
143 analyzer.cachedValues[value] = | |
144 builder.resolveUsageList(builder.convertConstantToUsageList(value)); | |
145 } else if (named.name.source == const SourceString('metaTargets')) { | |
146 analyzer.cachedValues[value] = | |
147 builder.resolveUsageList(builder.convertConstantToUsageList(value)); | |
148 } else if (named.name.source == const SourceString('override')) { | |
149 analyzer.cachedValues[value] = | |
150 builder.resolveUsageList(builder.convertConstantToUsageList(value)); | |
151 } | |
152 } | |
153 } | |
106 } | 154 } |
107 | 155 |
108 class MirrorUsageAnalyzer { | 156 class MirrorUsageAnalyzer { |
109 final Compiler compiler; | 157 final Compiler compiler; |
110 final MirrorUsageAnalyzerTask task; | 158 final MirrorUsageAnalyzerTask task; |
111 final List<LibraryElement> wildcard; | 159 List<LibraryElement> wildcard; |
112 final Set<LibraryElement> librariesWithUsage; | 160 final Set<LibraryElement> librariesWithUsage; |
113 final Set<LibraryElement> librariesWithoutUsage; | 161 final Map<Constant, List> cachedValues; |
114 MirrorUsage mergedMirrorUsage; | 162 MirrorUsage mergedMirrorUsage; |
115 | 163 |
116 MirrorUsageAnalyzer(Compiler compiler, this.task) | 164 MirrorUsageAnalyzer(Compiler compiler, this.task) |
117 : compiler = compiler, | 165 : compiler = compiler, |
118 wildcard = compiler.libraries.values.toList(), | |
119 librariesWithUsage = new Set<LibraryElement>(), | 166 librariesWithUsage = new Set<LibraryElement>(), |
120 librariesWithoutUsage = new Set<LibraryElement>(); | 167 cachedValues = new Map<Constant, List>(); |
121 | 168 |
122 void run() { | 169 void run() { |
170 wildcard = compiler.libraries.values.toList(); | |
123 Map<LibraryElement, List<MirrorUsage>> usageMap = | 171 Map<LibraryElement, List<MirrorUsage>> usageMap = |
124 collectMirrorsUsedAnnotation(); | 172 collectMirrorsUsedAnnotation(); |
125 propagateOverrides(usageMap); | 173 propagateOverrides(usageMap); |
126 librariesWithoutUsage.removeAll(usageMap.keys); | 174 Set<LibraryElement> librariesWithoutUsage = new Set<LibraryElement>(); |
175 usageMap.forEach((LibraryElement library, List<MirrorUsage> usage) { | |
176 if (usage.isEmpty) librariesWithoutUsage.add(library); | |
177 }); | |
127 if (librariesWithoutUsage.isEmpty) { | 178 if (librariesWithoutUsage.isEmpty) { |
128 mergedMirrorUsage = mergeUsages(usageMap); | 179 mergedMirrorUsage = mergeUsages(usageMap); |
129 } else { | 180 } else { |
130 mergedMirrorUsage = new MirrorUsage(null, wildcard, null, null); | 181 mergedMirrorUsage = new MirrorUsage(null, wildcard, null, null); |
131 } | 182 } |
132 } | 183 } |
133 | 184 |
134 Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() { | 185 Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() { |
135 Map<LibraryElement, List<MirrorUsage>> result = | 186 Map<LibraryElement, List<MirrorUsage>> result = |
136 new Map<LibraryElement, List<MirrorUsage>>(); | 187 new Map<LibraryElement, List<MirrorUsage>>(); |
137 for (LibraryElement library in compiler.libraries.values) { | 188 for (LibraryElement library in compiler.libraries.values) { |
138 if (library.isInternalLibrary) continue; | 189 if (library.isInternalLibrary) continue; |
139 librariesWithoutUsage.add(library); | |
140 for (LibraryTag tag in library.tags) { | 190 for (LibraryTag tag in library.tags) { |
141 Import importTag = tag.asImport(); | 191 Import importTag = tag.asImport(); |
142 if (importTag == null) continue; | 192 if (importTag == null) continue; |
143 compiler.withCurrentElement(library, () { | 193 compiler.withCurrentElement(library, () { |
144 List<MirrorUsage> usages = | 194 List<MirrorUsage> usages = |
145 mirrorsUsedOnLibraryTag(library, importTag); | 195 mirrorsUsedOnLibraryTag(library, importTag); |
146 if (usages != null) { | 196 if (usages != null) { |
147 List<MirrorUsage> existing = result[library]; | 197 List<MirrorUsage> existing = result[library]; |
148 if (existing != null) { | 198 if (existing != null) { |
149 existing.addAll(usages); | 199 existing.addAll(usages); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 Import tag) { | 243 Import tag) { |
194 LibraryElement importedLibrary = library.getLibraryFromTag(tag); | 244 LibraryElement importedLibrary = library.getLibraryFromTag(tag); |
195 if (importedLibrary != compiler.mirrorsLibrary) { | 245 if (importedLibrary != compiler.mirrorsLibrary) { |
196 return null; | 246 return null; |
197 } | 247 } |
198 List<MirrorUsage> result = <MirrorUsage>[]; | 248 List<MirrorUsage> result = <MirrorUsage>[]; |
199 for (MetadataAnnotation metadata in tag.metadata) { | 249 for (MetadataAnnotation metadata in tag.metadata) { |
200 metadata.ensureResolved(compiler); | 250 metadata.ensureResolved(compiler); |
201 Element element = metadata.value.computeType(compiler).element; | 251 Element element = metadata.value.computeType(compiler).element; |
202 if (element == compiler.mirrorsUsedClass) { | 252 if (element == compiler.mirrorsUsedClass) { |
203 try { | 253 result.add(buildUsage(metadata.value)); |
204 MirrorUsage usage = | |
205 new MirrorUsageBuilder(this, library).build(metadata.value); | |
206 result.add(usage); | |
207 } on BadMirrorsUsedAnnotation catch (e) { | |
208 compiler.reportError( | |
209 metadata, MessageKind.GENERIC, {'text': e.message}); | |
210 } | |
211 } | 254 } |
212 } | 255 } |
213 return result; | 256 return result; |
214 } | 257 } |
215 | 258 |
216 MirrorUsage mergeUsages(Map<LibraryElement, List<MirrorUsage>> usageMap) { | 259 MirrorUsage mergeUsages(Map<LibraryElement, List<MirrorUsage>> usageMap) { |
217 Set<MirrorUsage> usagesToMerge = new Set<MirrorUsage>(); | 260 Set<MirrorUsage> usagesToMerge = new Set<MirrorUsage>(); |
218 usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) { | 261 usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) { |
219 librariesWithUsage.add(library); | 262 librariesWithUsage.add(library); |
220 usagesToMerge.addAll(usages); | 263 usagesToMerge.addAll(usages); |
(...skipping 30 matching lines...) Expand all Loading... | |
251 targets.addAll(b.targets); | 294 targets.addAll(b.targets); |
252 } | 295 } |
253 List<Element> metaTargets = a.metaTargets; | 296 List<Element> metaTargets = a.metaTargets; |
254 if (metaTargets == null) { | 297 if (metaTargets == null) { |
255 metaTargets = b.metaTargets; | 298 metaTargets = b.metaTargets; |
256 } else if (metaTargets != wildcard && b.metaTargets != null) { | 299 } else if (metaTargets != wildcard && b.metaTargets != null) { |
257 metaTargets.addAll(b.metaTargets); | 300 metaTargets.addAll(b.metaTargets); |
258 } | 301 } |
259 return new MirrorUsage(symbols, targets, metaTargets, null); | 302 return new MirrorUsage(symbols, targets, metaTargets, null); |
260 } | 303 } |
304 | |
305 MirrorUsage buildUsage(ConstructedConstant constructedConstant) { | |
306 Map<Element, Constant> fields = constructedConstant.fieldElements; | |
307 VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember( | |
308 const SourceString('symbols')); | |
309 VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember( | |
310 const SourceString('targets')); | |
311 VariableElement metaTargetsField = | |
312 compiler.mirrorsUsedClass.lookupLocalMember( | |
313 const SourceString('metaTargets')); | |
314 VariableElement overrideField = compiler.mirrorsUsedClass.lookupLocalMember( | |
315 const SourceString('override')); | |
316 | |
317 return new MirrorUsage( | |
318 cachedValues[fields[symbolsField]], | |
319 cachedValues[fields[targetsField]], | |
320 cachedValues[fields[metaTargetsField]], | |
321 cachedValues[fields[overrideField]]); | |
322 } | |
261 } | 323 } |
262 | 324 |
263 class MirrorUsage { | 325 class MirrorUsage { |
264 final List<String> symbols; | 326 final List<String> symbols; |
265 final List<Element> targets; | 327 final List<Element> targets; |
266 final List<Element> metaTargets; | 328 final List<Element> metaTargets; |
267 final List<Element> override; | 329 final List<Element> override; |
268 | 330 |
269 MirrorUsage(this.symbols, this.targets, this.metaTargets, this.override); | 331 MirrorUsage(this.symbols, this.targets, this.metaTargets, this.override); |
270 | 332 |
271 String toString() { | 333 String toString() { |
272 return | 334 return |
273 'MirrorUsage(' | 335 'MirrorUsage(' |
274 'symbols = $symbols, ' | 336 'symbols = $symbols, ' |
275 'targets = $targets, ' | 337 'targets = $targets, ' |
276 'metaTargets = $metaTargets, ' | 338 'metaTargets = $metaTargets, ' |
277 'override = $override' | 339 'override = $override' |
278 ')'; | 340 ')'; |
279 | 341 |
280 } | 342 } |
281 } | 343 } |
282 | 344 |
283 class MirrorUsageBuilder { | 345 class MirrorUsageBuilder { |
284 MirrorUsageAnalyzer analyzer; | 346 final MirrorUsageAnalyzer analyzer; |
285 LibraryElement enclosingLibrary; | 347 final LibraryElement enclosingLibrary; |
348 final Spannable spannable; | |
349 final Constant constant; | |
350 final Map<Constant, Node> constantToNodeMap; | |
286 | 351 |
287 MirrorUsageBuilder(this.analyzer, this.enclosingLibrary); | 352 MirrorUsageBuilder( |
353 this.analyzer, | |
354 this.enclosingLibrary, | |
355 this.spannable, | |
356 this.constant, | |
357 this.constantToNodeMap); | |
288 | 358 |
289 Compiler get compiler => analyzer.compiler; | 359 Compiler get compiler => analyzer.compiler; |
290 | 360 |
291 MirrorUsage build(ConstructedConstant constant) { | 361 List convertConstantToUsageList( |
292 Map<Element, Constant> fields = constant.fieldElements; | 362 Constant constant, { bool onlyStrings: false }) { |
293 VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember( | |
294 const SourceString('symbols')); | |
295 VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember( | |
296 const SourceString('targets')); | |
297 VariableElement metaTargetsField = | |
298 compiler.mirrorsUsedClass.lookupLocalMember( | |
299 const SourceString('metaTargets')); | |
300 VariableElement overrideField = compiler.mirrorsUsedClass.lookupLocalMember( | |
301 const SourceString('override')); | |
302 List<String> symbols = | |
303 convertToListOfStrings( | |
304 convertConstantToUsageList(fields[symbolsField])); | |
305 List<Element> targets = | |
306 resolveUsageList(convertConstantToUsageList(fields[targetsField])); | |
307 | |
308 List<Element> metaTargets = | |
309 resolveUsageList(convertConstantToUsageList(fields[metaTargetsField])); | |
310 List<Element> override = | |
311 resolveUsageList(convertConstantToUsageList(fields[overrideField])); | |
312 return new MirrorUsage(symbols, targets, metaTargets, override); | |
313 } | |
314 | |
315 List convertConstantToUsageList(Constant constant) { | |
316 if (constant.isNull()) { | 363 if (constant.isNull()) { |
317 return null; | 364 return null; |
318 } else if (constant.isList()) { | 365 } else if (constant.isList()) { |
319 ListConstant list = constant; | 366 ListConstant list = constant; |
320 List result = []; | 367 List result = []; |
321 for (Constant entry in list.entries) { | 368 for (Constant entry in list.entries) { |
322 if (entry.isString()) { | 369 if (entry.isString()) { |
323 StringConstant string = entry; | 370 StringConstant string = entry; |
324 result.add(string.value.slowToString()); | 371 result.add(string.value.slowToString()); |
325 } else if (entry.isType()) { | 372 } else if (!onlyStrings && entry.isType()) { |
326 TypeConstant type = entry; | 373 TypeConstant type = entry; |
327 result.add(type.representedType); | 374 result.add(type.representedType); |
328 } else { | 375 } else { |
329 throw new BadMirrorsUsedAnnotation( | 376 Spannable node = positionOf(entry); |
330 'Expected a string or type, but got "$entry".'); | 377 MessageKind kind = onlyStrings |
378 ? MessageKind.MIRRORS_EXPECTED_STRING | |
379 : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE; | |
380 compiler.reportHint( | |
381 node, | |
382 kind, {'name': node, 'type': apiTypeOf(entry)}); | |
331 } | 383 } |
332 } | 384 } |
333 return result; | 385 return result; |
334 } else if (constant.isType()) { | 386 } else if (!onlyStrings && constant.isType()) { |
335 TypeConstant type = constant; | 387 TypeConstant type = constant; |
336 return [type.representedType]; | 388 return [type.representedType]; |
337 } else if (constant.isString()) { | 389 } else if (constant.isString()) { |
338 StringConstant string = constant; | 390 StringConstant string = constant; |
339 return | 391 return |
340 string.value.slowToString().split(',').map((e) => e.trim()).toList(); | 392 string.value.slowToString().split(',').map((e) => e.trim()).toList(); |
341 } else { | 393 } else { |
342 throw new BadMirrorsUsedAnnotation( | 394 Spannable node = positionOf(constant); |
343 'Expected a string or a list of string, but got "$constant".'); | 395 MessageKind kind = onlyStrings |
396 ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST | |
397 : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST; | |
398 compiler.reportHint( | |
399 node, | |
400 kind, {'name': node, 'type': apiTypeOf(constant)}); | |
401 return null; | |
344 } | 402 } |
345 } | 403 } |
346 | 404 |
405 DartType apiTypeOf(Constant constant) { | |
406 DartType type = constant.computeType(compiler); | |
Johnni Winther
2013/08/07 10:39:17
This doesn't work for double constants with zero f
ahe
2013/08/07 13:40:20
That sounds like a bug in our constant system.
| |
407 LibraryElement library = type.element.getLibrary(); | |
408 if (type.kind == TypeKind.INTERFACE && library.isInternalLibrary) { | |
409 InterfaceType interface = type; | |
410 ClassElement cls = type.element; | |
411 for (DartType supertype in cls.ensureResolved(compiler).allSupertypes) { | |
412 if (supertype.kind == TypeKind.INTERFACE | |
413 && !supertype.element.getLibrary().isInternalLibrary) { | |
414 return interface.asInstanceOf(supertype.element); | |
415 } | |
416 } | |
417 } | |
418 return type; | |
419 } | |
420 | |
347 List<String> convertToListOfStrings(List list) { | 421 List<String> convertToListOfStrings(List list) { |
348 if (list == null) return null; | 422 if (list == null) return null; |
349 List<String> result = new List<String>(list.length); | 423 List<String> result = new List<String>(list.length); |
350 int count = 0; | 424 int count = 0; |
351 for (var entry in list) { | 425 for (var entry in list) { |
352 if (entry is! String) { | 426 assert(invariant(spannable, entry is String)); |
353 throw new BadMirrorsUsedAnnotation( | |
354 'Expected a string, but got "$entry"'); | |
355 } | |
356 result[count++] = entry; | 427 result[count++] = entry; |
357 } | 428 } |
358 return result; | 429 return result; |
359 } | 430 } |
360 | 431 |
361 List<Element> resolveUsageList(List list) { | 432 List<Element> resolveUsageList(List list) { |
362 if (list == null) return null; | 433 if (list == null) return null; |
363 if (list.length == 1 && list[0] == '*') { | 434 if (list.length == 1 && list[0] == '*') { |
364 return analyzer.wildcard; | 435 return analyzer.wildcard; |
365 } | 436 } |
366 List<Element> result = <Element>[]; | 437 List<Element> result = <Element>[]; |
367 for (var entry in list) { | 438 for (var entry in list) { |
368 if (entry is DartType) { | 439 if (entry is DartType) { |
369 DartType type = entry; | 440 DartType type = entry; |
370 result.add(type.element); | 441 result.add(type.element); |
371 } else { | 442 } else { |
372 String string = entry; | 443 String string = entry; |
444 LibraryElement libraryCandiate; | |
445 String libraryNameCandiate; | |
373 for (LibraryElement l in compiler.libraries.values) { | 446 for (LibraryElement l in compiler.libraries.values) { |
374 if (l.hasLibraryName()) { | 447 if (l.hasLibraryName()) { |
375 String libraryName = l.getLibraryOrScriptName(); | 448 String libraryName = l.getLibraryOrScriptName(); |
376 if (string == libraryName || string.startsWith('$libraryName.')) { | 449 if (string == libraryName) { |
377 result.add(l); | 450 // Found an exact match. |
451 libraryCandiate = l; | |
452 libraryNameCandiate = libraryName; | |
378 break; | 453 break; |
454 } else if (string.startsWith('$libraryName.')) { | |
455 if (libraryNameCandiate == null | |
456 || libraryNameCandiate.length < libraryName.length) { | |
457 // Found a better candiate | |
458 libraryCandiate = l; | |
459 libraryNameCandiate = libraryName; | |
460 } | |
379 } | 461 } |
380 } | 462 } |
381 } | 463 } |
464 Element e; | |
465 if (libraryNameCandiate == string) { | |
466 e = libraryCandiate; | |
467 } else if (libraryNameCandiate != null) { | |
468 e = resolveLocalExpression( | |
469 libraryCandiate, | |
470 string.substring(libraryNameCandiate.length + 1).split('.')); | |
471 } else { | |
472 e = resolveExpression(string); | |
473 } | |
474 if (e != null) result.add(e); | |
382 } | 475 } |
383 } | 476 } |
384 return result; | 477 return result; |
385 } | 478 } |
479 | |
480 /// Resolve [expression] in [enclosingLibrary]'s import scope. | |
481 Element resolveExpression(String expression) { | |
482 List<String> identifiers = expression.split('.'); | |
483 Element element = enclosingLibrary.find(new SourceString(identifiers[0])); | |
484 if (element == null) { | |
485 compiler.reportHint( | |
486 spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY, | |
487 {'name': identifiers[0]}); | |
488 return null; | |
489 } else { | |
490 if (identifiers.length == 1) return element; | |
491 return resolveLocalExpression(element, identifiers.sublist(1)); | |
492 } | |
493 } | |
494 | |
495 /// Resolve [identifiers] in [element]'s local members. | |
496 Element resolveLocalExpression(Element element, List<String> identifiers) { | |
497 Element current = element; | |
498 for (String identifier in identifiers) { | |
499 Element e = findLocalMemberIn(current, new SourceString(identifier)); | |
500 if (e == null) { | |
501 if (current.isLibrary()) { | |
502 LibraryElement library = current; | |
503 compiler.reportHint( | |
504 spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY, | |
505 {'name': identifiers[0], | |
506 'library': library.getLibraryOrScriptName()}); | |
507 } else { | |
508 compiler.reportHint( | |
509 spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT, | |
510 {'name': identifier, 'element': current.name}); | |
511 } | |
512 return current; | |
513 } | |
514 current = e; | |
515 } | |
516 return current; | |
517 } | |
518 | |
519 Element findLocalMemberIn(Element element, SourceString name) { | |
520 if (element is ScopeContainerElement) { | |
521 ScopeContainerElement scope = element as dynamic; | |
522 return scope.localLookup(name); | |
523 } | |
524 return null; | |
525 } | |
526 | |
527 Spannable positionOf(Constant constant) { | |
528 Node node = constantToNodeMap[constant]; | |
529 if (node != null) { | |
530 // TODO(ahe): Returning [node] here leads to confusing error messages. | |
531 // For example, consider: | |
532 // @MirrorsUsed(targets: fisk) | |
533 // import 'dart:mirrors'; | |
534 // | |
535 // const fisk = const [main]; | |
536 // | |
537 // main() {} | |
538 // | |
539 // The message is: | |
540 // example.dart:1:23: Hint: Can't use 'fisk' here because ... | |
541 // Did you forget to add quotes? | |
542 // @MirrorsUsed(targets: fisk) | |
543 // ^^^^ | |
544 // | |
545 // Instead of saying 'fisk' should pretty print the problematic constant | |
546 // value. | |
547 return node; | |
548 } | |
549 return spannable; | |
550 } | |
386 } | 551 } |
387 | |
388 class BadMirrorsUsedAnnotation { | |
389 final String message; | |
390 BadMirrorsUsedAnnotation(this.message); | |
391 } | |
OLD | NEW |