Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: dart/sdk/lib/_internal/compiler/implementation/mirrors_used.dart

Issue 21242002: Retain elements a finer granularity than library. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Address review comments Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 '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
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
104 /// Collect @MirrorsUsed annotations in all libraries. Called by the
105 /// compiler after all libraries are loaded, but before resolution.
88 void analyzeUsage(LibraryElement mainApp) { 106 void analyzeUsage(LibraryElement mainApp) {
89 if (compiler.mirrorsLibrary == null) return; 107 if (compiler.mirrorsLibrary == null) return;
90 MirrorUsageAnalyzer analyzer = new MirrorUsageAnalyzer(compiler, this);
91 measure(analyzer.run); 108 measure(analyzer.run);
92 List<String> symbols = analyzer.mergedMirrorUsage.symbols; 109 List<String> symbols = analyzer.mergedMirrorUsage.symbols;
93 List<Element> targets = analyzer.mergedMirrorUsage.targets; 110 List<Element> targets = analyzer.mergedMirrorUsage.targets;
94 List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets; 111 List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets;
95 compiler.backend.registerMirrorUsage( 112 compiler.backend.registerMirrorUsage(
96 symbols == null ? null : new Set<String>.from(symbols), 113 symbols == null ? null : new Set<String>.from(symbols),
97 targets == null ? null : new Set<Element>.from(targets), 114 targets == null ? null : new Set<Element>.from(targets),
98 metaTargets == null ? null : new Set<Element>.from(metaTargets)); 115 metaTargets == null ? null : new Set<Element>.from(metaTargets));
99 librariesWithUsage = analyzer.librariesWithUsage; 116 librariesWithUsage = analyzer.librariesWithUsage;
100 } 117 }
101 118
119 /// Is there a @MirrorsUsed annotation in the library of [element]? Used by
120 /// the resolver to suppress hints about using new Symbol or
121 /// MirrorSystem.getName.
102 bool hasMirrorUsage(Element element) { 122 bool hasMirrorUsage(Element element) {
103 return librariesWithUsage != null 123 return librariesWithUsage != null
104 && librariesWithUsage.contains(element.getLibrary()); 124 && librariesWithUsage.contains(element.getLibrary());
105 } 125 }
126
127 /// Call-back from the resolver to analyze MirorsUsed annotations. The result
128 /// is stored in [analyzer] and later used to compute
129 /// [:analyzer.mergedMirrorUsage:].
130 void validate(NewExpression node, TreeElements mapping) {
131 for (Node argument in node.send.arguments) {
132 NamedArgument named = argument.asNamedArgument();
133 if (named == null) continue;
134 Constant value = compiler.metadataHandler.compileNodeWithDefinitions(
135 named.expression, mapping, isConst: true);
136
137 ConstantMapper mapper =
138 new ConstantMapper(compiler.metadataHandler, mapping, compiler);
139 named.expression.accept(mapper);
140
141 MirrorUsageBuilder builder =
142 new MirrorUsageBuilder(
143 analyzer, mapping.currentElement.getLibrary(), named.expression,
144 value, mapper.constantToNodeMap);
145
146 if (named.name.source == const SourceString('symbols')) {
147 analyzer.cachedValues[value] =
148 builder.convertToListOfStrings(
149 builder.convertConstantToUsageList(value, onlyStrings: true));
150 } else if (named.name.source == const SourceString('targets')) {
151 analyzer.cachedValues[value] =
152 builder.resolveUsageList(builder.convertConstantToUsageList(value));
153 } else if (named.name.source == const SourceString('metaTargets')) {
154 analyzer.cachedValues[value] =
155 builder.resolveUsageList(builder.convertConstantToUsageList(value));
156 } else if (named.name.source == const SourceString('override')) {
157 analyzer.cachedValues[value] =
158 builder.resolveUsageList(builder.convertConstantToUsageList(value));
159 }
160 }
161 }
106 } 162 }
107 163
108 class MirrorUsageAnalyzer { 164 class MirrorUsageAnalyzer {
109 final Compiler compiler; 165 final Compiler compiler;
110 final MirrorUsageAnalyzerTask task; 166 final MirrorUsageAnalyzerTask task;
111 final List<LibraryElement> wildcard; 167 List<LibraryElement> wildcard;
112 final Set<LibraryElement> librariesWithUsage; 168 final Set<LibraryElement> librariesWithUsage;
113 final Set<LibraryElement> librariesWithoutUsage; 169 final Map<Constant, List> cachedValues;
114 MirrorUsage mergedMirrorUsage; 170 MirrorUsage mergedMirrorUsage;
115 171
116 MirrorUsageAnalyzer(Compiler compiler, this.task) 172 MirrorUsageAnalyzer(Compiler compiler, this.task)
117 : compiler = compiler, 173 : compiler = compiler,
118 wildcard = compiler.libraries.values.toList(),
119 librariesWithUsage = new Set<LibraryElement>(), 174 librariesWithUsage = new Set<LibraryElement>(),
120 librariesWithoutUsage = new Set<LibraryElement>(); 175 cachedValues = new Map<Constant, List>();
121 176
177 /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also
178 /// compute which libraries have the annotation (which is used by
179 /// [MirrorUsageAnalyzerTask.hasMirrorUsage]).
122 void run() { 180 void run() {
181 wildcard = compiler.libraries.values.toList();
123 Map<LibraryElement, List<MirrorUsage>> usageMap = 182 Map<LibraryElement, List<MirrorUsage>> usageMap =
124 collectMirrorsUsedAnnotation(); 183 collectMirrorsUsedAnnotation();
125 propagateOverrides(usageMap); 184 propagateOverrides(usageMap);
126 librariesWithoutUsage.removeAll(usageMap.keys); 185 Set<LibraryElement> librariesWithoutUsage = new Set<LibraryElement>();
186 usageMap.forEach((LibraryElement library, List<MirrorUsage> usage) {
187 if (usage.isEmpty) librariesWithoutUsage.add(library);
188 });
127 if (librariesWithoutUsage.isEmpty) { 189 if (librariesWithoutUsage.isEmpty) {
128 mergedMirrorUsage = mergeUsages(usageMap); 190 mergedMirrorUsage = mergeUsages(usageMap);
129 } else { 191 } else {
130 mergedMirrorUsage = new MirrorUsage(null, wildcard, null, null); 192 mergedMirrorUsage = new MirrorUsage(null, wildcard, null, null);
131 } 193 }
132 } 194 }
133 195
196 /// Collect all @MirrorsUsed from all libraries and represent them as
197 /// [MirrorUsage].
134 Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() { 198 Map<LibraryElement, List<MirrorUsage>> collectMirrorsUsedAnnotation() {
135 Map<LibraryElement, List<MirrorUsage>> result = 199 Map<LibraryElement, List<MirrorUsage>> result =
136 new Map<LibraryElement, List<MirrorUsage>>(); 200 new Map<LibraryElement, List<MirrorUsage>>();
137 for (LibraryElement library in compiler.libraries.values) { 201 for (LibraryElement library in compiler.libraries.values) {
138 if (library.isInternalLibrary) continue; 202 if (library.isInternalLibrary) continue;
139 librariesWithoutUsage.add(library);
140 for (LibraryTag tag in library.tags) { 203 for (LibraryTag tag in library.tags) {
141 Import importTag = tag.asImport(); 204 Import importTag = tag.asImport();
142 if (importTag == null) continue; 205 if (importTag == null) continue;
143 compiler.withCurrentElement(library, () { 206 compiler.withCurrentElement(library, () {
144 List<MirrorUsage> usages = 207 List<MirrorUsage> usages =
145 mirrorsUsedOnLibraryTag(library, importTag); 208 mirrorsUsedOnLibraryTag(library, importTag);
146 if (usages != null) { 209 if (usages != null) {
147 List<MirrorUsage> existing = result[library]; 210 List<MirrorUsage> existing = result[library];
148 if (existing != null) { 211 if (existing != null) {
149 existing.addAll(usages); 212 existing.addAll(usages);
150 } else { 213 } else {
151 result[library] = usages; 214 result[library] = usages;
152 } 215 }
153 } 216 }
154 }); 217 });
155 } 218 }
156 } 219 }
157 return result; 220 return result;
158 } 221 }
159 222
223 /// Apply [MirrorUsage] with 'override' to libraries they override.
160 void propagateOverrides(Map<LibraryElement, List<MirrorUsage>> usageMap) { 224 void propagateOverrides(Map<LibraryElement, List<MirrorUsage>> usageMap) {
161 Map<LibraryElement, List<MirrorUsage>> propagatedOverrides = 225 Map<LibraryElement, List<MirrorUsage>> propagatedOverrides =
162 new Map<LibraryElement, List<MirrorUsage>>(); 226 new Map<LibraryElement, List<MirrorUsage>>();
163 usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) { 227 usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) {
164 for (MirrorUsage usage in usages) { 228 for (MirrorUsage usage in usages) {
165 List<Element> override = usage.override; 229 List<Element> override = usage.override;
166 if (override == null) continue; 230 if (override == null) continue;
167 if (override == wildcard) { 231 if (override == wildcard) {
168 for (LibraryElement overridden in wildcard) { 232 for (LibraryElement overridden in wildcard) {
169 if (overridden != library) { 233 if (overridden != library) {
(...skipping 12 matching lines...) Expand all
182 } 246 }
183 }); 247 });
184 propagatedOverrides.forEach((LibraryElement overridden, 248 propagatedOverrides.forEach((LibraryElement overridden,
185 List<MirrorUsage> overriddenUsages) { 249 List<MirrorUsage> overriddenUsages) {
186 List<MirrorUsage> usages = 250 List<MirrorUsage> usages =
187 usageMap.putIfAbsent(overridden, () => <MirrorUsage>[]); 251 usageMap.putIfAbsent(overridden, () => <MirrorUsage>[]);
188 usages.addAll(overriddenUsages); 252 usages.addAll(overriddenUsages);
189 }); 253 });
190 } 254 }
191 255
256 /// Find @MirrorsUsed annotations on the given import [tag] in [library]. The
257 /// annotations are represented as [MirrorUsage].
192 List<MirrorUsage> mirrorsUsedOnLibraryTag(LibraryElement library, 258 List<MirrorUsage> mirrorsUsedOnLibraryTag(LibraryElement library,
193 Import tag) { 259 Import tag) {
194 LibraryElement importedLibrary = library.getLibraryFromTag(tag); 260 LibraryElement importedLibrary = library.getLibraryFromTag(tag);
195 if (importedLibrary != compiler.mirrorsLibrary) { 261 if (importedLibrary != compiler.mirrorsLibrary) {
196 return null; 262 return null;
197 } 263 }
198 List<MirrorUsage> result = <MirrorUsage>[]; 264 List<MirrorUsage> result = <MirrorUsage>[];
199 for (MetadataAnnotation metadata in tag.metadata) { 265 for (MetadataAnnotation metadata in tag.metadata) {
200 metadata.ensureResolved(compiler); 266 metadata.ensureResolved(compiler);
201 Element element = metadata.value.computeType(compiler).element; 267 Element element = metadata.value.computeType(compiler).element;
202 if (element == compiler.mirrorsUsedClass) { 268 if (element == compiler.mirrorsUsedClass) {
203 try { 269 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 } 270 }
212 } 271 }
213 return result; 272 return result;
214 } 273 }
215 274
275 /// Merge all [MirrorUsage] instances accross all libraries.
216 MirrorUsage mergeUsages(Map<LibraryElement, List<MirrorUsage>> usageMap) { 276 MirrorUsage mergeUsages(Map<LibraryElement, List<MirrorUsage>> usageMap) {
217 Set<MirrorUsage> usagesToMerge = new Set<MirrorUsage>(); 277 Set<MirrorUsage> usagesToMerge = new Set<MirrorUsage>();
218 usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) { 278 usageMap.forEach((LibraryElement library, List<MirrorUsage> usages) {
219 librariesWithUsage.add(library); 279 librariesWithUsage.add(library);
220 usagesToMerge.addAll(usages); 280 usagesToMerge.addAll(usages);
221 }); 281 });
222 if (usagesToMerge.isEmpty) { 282 if (usagesToMerge.isEmpty) {
223 return new MirrorUsage(null, wildcard, null, null); 283 return new MirrorUsage(null, wildcard, null, null);
224 } else { 284 } else {
225 MirrorUsage result = new MirrorUsage(null, null, null, null); 285 MirrorUsage result = new MirrorUsage(null, null, null, null);
226 for (MirrorUsage usage in usagesToMerge) { 286 for (MirrorUsage usage in usagesToMerge) {
227 result = merge(result, usage); 287 result = merge(result, usage);
228 } 288 }
229 return result; 289 return result;
230 } 290 }
231 } 291 }
232 292
293 /// Merge [a] with [b]. The resulting [MirrorUsage] simply has the symbols,
294 /// targets, and metaTargets of [a] and [b] concatenated. 'override' is
295 /// ignored.
233 MirrorUsage merge(MirrorUsage a, MirrorUsage b) { 296 MirrorUsage merge(MirrorUsage a, MirrorUsage b) {
297 // TOOO(ahe): Should be an instance method on MirrorUsage.
234 if (a.symbols == null && a.targets == null && a.metaTargets == null) { 298 if (a.symbols == null && a.targets == null && a.metaTargets == null) {
235 return b; 299 return b;
236 } else if ( 300 } else if (
237 b.symbols == null && b.targets == null && b.metaTargets == null) { 301 b.symbols == null && b.targets == null && b.metaTargets == null) {
238 return a; 302 return a;
239 } 303 }
240 // TODO(ahe): Test the following cases. 304 // TODO(ahe): Test the following cases.
241 List<String> symbols = a.symbols; 305 List<String> symbols = a.symbols;
242 if (symbols == null) { 306 if (symbols == null) {
243 symbols = b.symbols; 307 symbols = b.symbols;
244 } else if (b.symbols != null) { 308 } else if (b.symbols != null) {
245 symbols.addAll(b.symbols); 309 symbols.addAll(b.symbols);
246 } 310 }
247 List<Element> targets = a.targets; 311 List<Element> targets = a.targets;
248 if (targets == null) { 312 if (targets == null) {
249 targets = b.targets; 313 targets = b.targets;
250 } else if (targets != wildcard && b.targets != null) { 314 } else if (targets != wildcard && b.targets != null) {
251 targets.addAll(b.targets); 315 targets.addAll(b.targets);
252 } 316 }
253 List<Element> metaTargets = a.metaTargets; 317 List<Element> metaTargets = a.metaTargets;
254 if (metaTargets == null) { 318 if (metaTargets == null) {
255 metaTargets = b.metaTargets; 319 metaTargets = b.metaTargets;
256 } else if (metaTargets != wildcard && b.metaTargets != null) { 320 } else if (metaTargets != wildcard && b.metaTargets != null) {
257 metaTargets.addAll(b.metaTargets); 321 metaTargets.addAll(b.metaTargets);
258 } 322 }
259 return new MirrorUsage(symbols, targets, metaTargets, null); 323 return new MirrorUsage(symbols, targets, metaTargets, null);
260 } 324 }
325
326 /// Convert a [constant] to an instance of [MirrorUsage] using information
327 /// that was resolved during [MirrorUsageAnalyzerTask.validate].
328 MirrorUsage buildUsage(ConstructedConstant constant) {
329 Map<Element, Constant> fields = constant.fieldElements;
330 VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember(
331 const SourceString('symbols'));
332 VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember(
333 const SourceString('targets'));
334 VariableElement metaTargetsField =
335 compiler.mirrorsUsedClass.lookupLocalMember(
336 const SourceString('metaTargets'));
337 VariableElement overrideField = compiler.mirrorsUsedClass.lookupLocalMember(
338 const SourceString('override'));
339
340 return new MirrorUsage(
341 cachedValues[fields[symbolsField]],
342 cachedValues[fields[targetsField]],
343 cachedValues[fields[metaTargetsField]],
344 cachedValues[fields[overrideField]]);
345 }
261 } 346 }
262 347
348 /// Used to represent a resolved MirrorsUsed constant.
263 class MirrorUsage { 349 class MirrorUsage {
264 final List<String> symbols; 350 final List<String> symbols;
265 final List<Element> targets; 351 final List<Element> targets;
266 final List<Element> metaTargets; 352 final List<Element> metaTargets;
267 final List<Element> override; 353 final List<Element> override;
268 354
269 MirrorUsage(this.symbols, this.targets, this.metaTargets, this.override); 355 MirrorUsage(this.symbols, this.targets, this.metaTargets, this.override);
270 356
271 String toString() { 357 String toString() {
272 return 358 return
273 'MirrorUsage(' 359 'MirrorUsage('
274 'symbols = $symbols, ' 360 'symbols = $symbols, '
275 'targets = $targets, ' 361 'targets = $targets, '
276 'metaTargets = $metaTargets, ' 362 'metaTargets = $metaTargets, '
277 'override = $override' 363 'override = $override'
278 ')'; 364 ')';
279 365
280 } 366 }
281 } 367 }
282 368
283 class MirrorUsageBuilder { 369 class MirrorUsageBuilder {
284 MirrorUsageAnalyzer analyzer; 370 final MirrorUsageAnalyzer analyzer;
285 LibraryElement enclosingLibrary; 371 final LibraryElement enclosingLibrary;
372 final Spannable spannable;
373 final Constant constant;
374 final Map<Constant, Node> constantToNodeMap;
286 375
287 MirrorUsageBuilder(this.analyzer, this.enclosingLibrary); 376 MirrorUsageBuilder(
377 this.analyzer,
378 this.enclosingLibrary,
379 this.spannable,
380 this.constant,
381 this.constantToNodeMap);
288 382
289 Compiler get compiler => analyzer.compiler; 383 Compiler get compiler => analyzer.compiler;
290 384
291 MirrorUsage build(ConstructedConstant constant) { 385 /// Convert a constant to a list of [String] and [Type] values. If the
292 Map<Element, Constant> fields = constant.fieldElements; 386 /// constant is a single [String], it is assumed to be a comma-separated list
293 VariableElement symbolsField = compiler.mirrorsUsedClass.lookupLocalMember( 387 /// of qualified names. If the constant is a [Type] t, the result is [:[t]:].
294 const SourceString('symbols')); 388 /// Otherwise, the constant is assumed to represent a list of strings (each a
295 VariableElement targetsField = compiler.mirrorsUsedClass.lookupLocalMember( 389 /// qualified name) and types, and such a list is constructed.
296 const SourceString('targets')); 390 List convertConstantToUsageList(
297 VariableElement metaTargetsField = 391 Constant constant, { bool onlyStrings: false }) {
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()) { 392 if (constant.isNull()) {
317 return null; 393 return null;
318 } else if (constant.isList()) { 394 } else if (constant.isList()) {
319 ListConstant list = constant; 395 ListConstant list = constant;
320 List result = []; 396 List result = [];
321 for (Constant entry in list.entries) { 397 for (Constant entry in list.entries) {
322 if (entry.isString()) { 398 if (entry.isString()) {
323 StringConstant string = entry; 399 StringConstant string = entry;
324 result.add(string.value.slowToString()); 400 result.add(string.value.slowToString());
325 } else if (entry.isType()) { 401 } else if (!onlyStrings && entry.isType()) {
326 TypeConstant type = entry; 402 TypeConstant type = entry;
327 result.add(type.representedType); 403 result.add(type.representedType);
328 } else { 404 } else {
329 throw new BadMirrorsUsedAnnotation( 405 Spannable node = positionOf(entry);
330 'Expected a string or type, but got "$entry".'); 406 MessageKind kind = onlyStrings
407 ? MessageKind.MIRRORS_EXPECTED_STRING
408 : MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE;
409 compiler.reportHint(
410 node,
411 kind, {'name': node, 'type': apiTypeOf(entry)});
331 } 412 }
332 } 413 }
333 return result; 414 return result;
334 } else if (constant.isType()) { 415 } else if (!onlyStrings && constant.isType()) {
335 TypeConstant type = constant; 416 TypeConstant type = constant;
336 return [type.representedType]; 417 return [type.representedType];
337 } else if (constant.isString()) { 418 } else if (constant.isString()) {
338 StringConstant string = constant; 419 StringConstant string = constant;
339 return 420 return
340 string.value.slowToString().split(',').map((e) => e.trim()).toList(); 421 string.value.slowToString().split(',').map((e) => e.trim()).toList();
341 } else { 422 } else {
342 throw new BadMirrorsUsedAnnotation( 423 Spannable node = positionOf(constant);
343 'Expected a string or a list of string, but got "$constant".'); 424 MessageKind kind = onlyStrings
425 ? MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST
426 : MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST;
427 compiler.reportHint(
428 node,
429 kind, {'name': node, 'type': apiTypeOf(constant)});
430 return null;
344 } 431 }
345 } 432 }
346 433
434 /// Find the first non-implementation interface of constant.
435 DartType apiTypeOf(Constant constant) {
436 DartType type = constant.computeType(compiler);
437 LibraryElement library = type.element.getLibrary();
438 if (type.kind == TypeKind.INTERFACE && library.isInternalLibrary) {
439 InterfaceType interface = type;
440 ClassElement cls = type.element;
441 for (DartType supertype in cls.ensureResolved(compiler).allSupertypes) {
442 if (supertype.kind == TypeKind.INTERFACE
443 && !supertype.element.getLibrary().isInternalLibrary) {
444 return interface.asInstanceOf(supertype.element);
445 }
446 }
447 }
448 return type;
449 }
450
451 /// Ensure a list contains only strings.
347 List<String> convertToListOfStrings(List list) { 452 List<String> convertToListOfStrings(List list) {
348 if (list == null) return null; 453 if (list == null) return null;
349 List<String> result = new List<String>(list.length); 454 List<String> result = new List<String>(list.length);
350 int count = 0; 455 int count = 0;
351 for (var entry in list) { 456 for (var entry in list) {
352 if (entry is! String) { 457 assert(invariant(spannable, entry is String));
353 throw new BadMirrorsUsedAnnotation(
354 'Expected a string, but got "$entry"');
355 }
356 result[count++] = entry; 458 result[count++] = entry;
357 } 459 }
358 return result; 460 return result;
359 } 461 }
360 462
463 /// Convert a list of strings and types to a list of elements. Types are
464 /// converted to their corresponding element, and strings are resolved as
465 /// follows:
466 ///
467 /// First find the longest library name that is a prefix of the string, if
468 /// there are none, resolve using [resolveExpression]. Otherwise, resolve the
469 /// rest of the string using [resolveLocalExpression].
361 List<Element> resolveUsageList(List list) { 470 List<Element> resolveUsageList(List list) {
362 if (list == null) return null; 471 if (list == null) return null;
363 if (list.length == 1 && list[0] == '*') { 472 if (list.length == 1 && list[0] == '*') {
364 return analyzer.wildcard; 473 return analyzer.wildcard;
365 } 474 }
366 List<Element> result = <Element>[]; 475 List<Element> result = <Element>[];
367 for (var entry in list) { 476 for (var entry in list) {
368 if (entry is DartType) { 477 if (entry is DartType) {
369 DartType type = entry; 478 DartType type = entry;
370 result.add(type.element); 479 result.add(type.element);
371 } else { 480 } else {
372 String string = entry; 481 String string = entry;
482 LibraryElement libraryCandiate;
483 String libraryNameCandiate;
373 for (LibraryElement l in compiler.libraries.values) { 484 for (LibraryElement l in compiler.libraries.values) {
374 if (l.hasLibraryName()) { 485 if (l.hasLibraryName()) {
375 String libraryName = l.getLibraryOrScriptName(); 486 String libraryName = l.getLibraryOrScriptName();
376 if (string == libraryName || string.startsWith('$libraryName.')) { 487 if (string == libraryName) {
377 result.add(l); 488 // Found an exact match.
489 libraryCandiate = l;
490 libraryNameCandiate = libraryName;
378 break; 491 break;
492 } else if (string.startsWith('$libraryName.')) {
493 if (libraryNameCandiate == null
494 || libraryNameCandiate.length < libraryName.length) {
495 // Found a better candiate
496 libraryCandiate = l;
497 libraryNameCandiate = libraryName;
498 }
379 } 499 }
380 } 500 }
381 } 501 }
502 Element e;
503 if (libraryNameCandiate == string) {
504 e = libraryCandiate;
505 } else if (libraryNameCandiate != null) {
506 e = resolveLocalExpression(
507 libraryCandiate,
508 string.substring(libraryNameCandiate.length + 1).split('.'));
509 } else {
510 e = resolveExpression(string);
511 }
512 if (e != null) result.add(e);
382 } 513 }
383 } 514 }
384 return result; 515 return result;
385 } 516 }
517
518 /// Resolve [expression] in [enclosingLibrary]'s import scope.
519 Element resolveExpression(String expression) {
520 List<String> identifiers = expression.split('.');
521 Element element = enclosingLibrary.find(new SourceString(identifiers[0]));
522 if (element == null) {
523 compiler.reportHint(
524 spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
525 {'name': expression});
526 return null;
527 } else {
528 if (identifiers.length == 1) return element;
529 return resolveLocalExpression(element, identifiers.sublist(1));
530 }
531 }
532
533 /// Resolve [identifiers] in [element]'s local members.
534 Element resolveLocalExpression(Element element, List<String> identifiers) {
535 Element current = element;
536 for (String identifier in identifiers) {
537 Element e = findLocalMemberIn(current, new SourceString(identifier));
538 if (e == null) {
539 if (current.isLibrary()) {
540 LibraryElement library = current;
541 compiler.reportHint(
542 spannable, MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
543 {'name': identifiers[0],
544 'library': library.getLibraryOrScriptName()});
545 } else {
546 compiler.reportHint(
547 spannable, MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
548 {'name': identifier, 'element': current.name});
549 }
550 return current;
551 }
552 current = e;
553 }
554 return current;
555 }
556
557 /// Helper method to lookup members in a [ScopeContainerElement]. If
558 /// [element] is not a ScopeContainerElement, return null.
559 Element findLocalMemberIn(Element element, SourceString name) {
560 if (element is ScopeContainerElement) {
561 ScopeContainerElement scope = element;
562 return scope.localLookup(name);
563 }
564 return null;
565 }
566
567 /// Attempt to find a [Spannable] corresponding to constant.
568 Spannable positionOf(Constant constant) {
569 Node node = constantToNodeMap[constant];
570 if (node == null) {
571 // TODO(ahe): Returning [spannable] here leads to confusing error
572 // messages. For example, consider:
573 // @MirrorsUsed(targets: fisk)
574 // import 'dart:mirrors';
575 //
576 // const fisk = const [main];
577 //
578 // main() {}
579 //
580 // The message is:
581 // example.dart:1:23: Hint: Can't use 'fisk' here because ...
582 // Did you forget to add quotes?
583 // @MirrorsUsed(targets: fisk)
584 // ^^^^
585 //
586 // Instead of saying 'fisk' should pretty print the problematic constant
587 // value.
588 return spannable;
589 }
590 return node;
591 }
386 } 592 }
387
388 class BadMirrorsUsedAnnotation {
389 final String message;
390 BadMirrorsUsedAnnotation(this.message);
391 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698