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

Side by Side Diff: lib/transformer.dart

Issue 1004033004: Fix initialize transformer crash on some programs (Closed) Base URL: git@github.com:dart-lang/static-init.git@master
Patch Set: Created 5 years, 9 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
« no previous file with comments | « lib/src/mirror_loader.dart ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library initialize.transformer; 4 library initialize.transformer;
5 5
6 import 'dart:async'; 6 import 'dart:async';
7 import 'dart:collection' show Queue; 7 import 'dart:collection' show Queue;
8 import 'package:analyzer/src/generated/ast.dart'; 8 import 'package:analyzer/src/generated/ast.dart';
9 import 'package:analyzer/src/generated/element.dart'; 9 import 'package:analyzer/src/generated/element.dart';
10 import 'package:barback/barback.dart'; 10 import 'package:barback/barback.dart';
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 bool isPrimary(AssetId id) => _entryPointGlobs.any((g) => g.matches(id.path)); 55 bool isPrimary(AssetId id) => _entryPointGlobs.any((g) => g.matches(id.path));
56 56
57 Future apply(Transform transform) { 57 Future apply(Transform transform) {
58 if (transform.primaryInput.id.path.endsWith('.dart')) { 58 if (transform.primaryInput.id.path.endsWith('.dart')) {
59 return _buildBootstrapFile(transform); 59 return _buildBootstrapFile(transform);
60 } else if (transform.primaryInput.id.path.endsWith('.html')) { 60 } else if (transform.primaryInput.id.path.endsWith('.html')) {
61 return transform.primaryInput.readAsString().then((html) { 61 return transform.primaryInput.readAsString().then((html) {
62 var document = parse(html); 62 var document = parse(html);
63 var originalDartFile = 63 var originalDartFile =
64 _findMainScript(document, transform.primaryInput.id, transform); 64 _findMainScript(document, transform.primaryInput.id, transform);
65 return _buildBootstrapFile(transform, primaryId: originalDartFile).then( 65 return _buildBootstrapFile(transform, primaryId: originalDartFile)
66 (AssetId newDartFile) { 66 .then((AssetId newDartFile) {
67 return _replaceEntryWithBootstrap(transform, document, 67 return _replaceEntryWithBootstrap(transform, document,
68 transform.primaryInput.id, originalDartFile, newDartFile); 68 transform.primaryInput.id, originalDartFile, newDartFile);
69 }); 69 });
70 }); 70 });
71 } else { 71 } else {
72 transform.logger.warning( 72 transform.logger.warning(
73 'Invalid entry point ${transform.primaryInput.id}. Must be either a ' 73 'Invalid entry point ${transform.primaryInput.id}. Must be either a '
74 '.dart or .html file.'); 74 '.dart or .html file.');
75 } 75 }
76 return new Future.value(); 76 return new Future.value();
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 '(possibly transitive).'); 226 '(possibly transitive).');
227 } 227 }
228 superClass = superClass.superclass; 228 superClass = superClass.superclass;
229 } 229 }
230 _readAnnotations(clazz); 230 _readAnnotations(clazz);
231 } 231 }
232 } 232 }
233 233
234 bool _readAnnotations(Element element) { 234 bool _readAnnotations(Element element) {
235 var found = false; 235 var found = false;
236 element.metadata.where((ElementAnnotation meta) { 236 if (element.metadata.isEmpty) return found;
237
238 var metaNodes;
239 var node = element.node;
240 if (node is SimpleIdentifier && node.parent is LibraryIdentifier) {
241 metaNodes = node.parent.parent.metadata;
242 } else if (node is ClassDeclaration || node is FunctionDeclaration) {
243 metaNodes = node.metadata;
244 } else {
245 return found;
246 }
247
248 metaNodes.where((Annotation metaNode) {
237 // First filter out anything that is not a Initializer. 249 // First filter out anything that is not a Initializer.
250 var meta = metaNode.elementAnnotation;
238 var e = meta.element; 251 var e = meta.element;
239 if (e is PropertyAccessorElement) { 252 if (e is PropertyAccessorElement) {
240 return _isInitializer(e.variable.evaluationResult.value.type); 253 return _isInitializer(e.variable.evaluationResult.value.type);
241 } else if (e is ConstructorElement) { 254 } else if (e is ConstructorElement) {
242 return _isInitializer(e.returnType); 255 return _isInitializer(e.returnType);
243 } 256 }
244 return false; 257 return false;
245 }).where((ElementAnnotation meta) { 258 }).where((Annotation metaNode) {
259 var meta = metaNode.elementAnnotation;
246 _seenAnnotations.putIfAbsent(element, () => new Set<ElementAnnotation>()); 260 _seenAnnotations.putIfAbsent(element, () => new Set<ElementAnnotation>());
247 return !_seenAnnotations[element].contains(meta); 261 return !_seenAnnotations[element].contains(meta);
248 }).forEach((ElementAnnotation meta) { 262 }).forEach((Annotation metaNode) {
263 var meta = metaNode.elementAnnotation;
249 _seenAnnotations[element].add(meta); 264 _seenAnnotations[element].add(meta);
250 _initQueue.addLast(new InitializerData._(element, meta)); 265 _initQueue.addLast(new InitializerData._(node, metaNode));
251 found = true; 266 found = true;
252 }); 267 });
253 return found; 268 return found;
254 } 269 }
255 270
256 String _buildNewEntryPoint(LibraryElement entryLib) { 271 String _buildNewEntryPoint(LibraryElement entryLib) {
257 var importsBuffer = new StringBuffer(); 272 var importsBuffer = new StringBuffer();
258 var initializersBuffer = new StringBuffer(); 273 var initializersBuffer = new StringBuffer();
259 var libraryPrefixes = new Map<LibraryElement, String>(); 274 var libraryPrefixes = new Map<LibraryElement, String>();
260 275
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) { 318 _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) {
304 AssetId id = (lib.source as dynamic).assetId; 319 AssetId id = (lib.source as dynamic).assetId;
305 320
306 if (id.path.startsWith('lib/')) { 321 if (id.path.startsWith('lib/')) {
307 var packagePath = id.path.replaceFirst('lib/', ''); 322 var packagePath = id.path.replaceFirst('lib/', '');
308 buffer.write("import 'package:${id.package}/${packagePath}'"); 323 buffer.write("import 'package:${id.package}/${packagePath}'");
309 } else if (id.package != _newEntryPoint.package) { 324 } else if (id.package != _newEntryPoint.package) {
310 _logger.error("Can't import `${id}` from `${_newEntryPoint}`"); 325 _logger.error("Can't import `${id}` from `${_newEntryPoint}`");
311 } else if (path.url.split(id.path)[0] == 326 } else if (path.url.split(id.path)[0] ==
312 path.url.split(_newEntryPoint.path)[0]) { 327 path.url.split(_newEntryPoint.path)[0]) {
313 var relativePath = path.url.relative( 328 var relativePath = path.url.relative(id.path,
314 id.path, from: path.url.dirname(_newEntryPoint.path)); 329 from: path.url.dirname(_newEntryPoint.path));
315 buffer.write("import '${relativePath}'"); 330 buffer.write("import '${relativePath}'");
316 } else { 331 } else {
317 _logger.error("Can't import `${id}` from `${_newEntryPoint}`"); 332 _logger.error("Can't import `${id}` from `${_newEntryPoint}`");
318 } 333 }
319 buffer.writeln(' as $prefix;'); 334 buffer.writeln(' as $prefix;');
320 } 335 }
321 336
322 bool _isInitializer(InterfaceType type) { 337 bool _isInitializer(InterfaceType type) {
323 // If `_initializer` wasn't found then it was never loaded (even 338 // If `_initializer` wasn't found then it was never loaded (even
324 // transitively), and so no annotations can be initializers. 339 // transitively), and so no annotations can be initializers.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 Iterable<LibraryElement> _sortedLibraryDependencies(LibraryElement library) { 396 Iterable<LibraryElement> _sortedLibraryDependencies(LibraryElement library) {
382 // TODO(jakemac): Investigate supporting annotations on part-of directives. 397 // TODO(jakemac): Investigate supporting annotations on part-of directives.
383 getLibrary(UriReferencedElement element) { 398 getLibrary(UriReferencedElement element) {
384 if (element is ImportElement) return element.importedLibrary; 399 if (element is ImportElement) return element.importedLibrary;
385 if (element is ExportElement) return element.exportedLibrary; 400 if (element is ExportElement) return element.exportedLibrary;
386 } 401 }
387 402
388 return (new List.from(library.imports) 403 return (new List.from(library.imports)
389 ..addAll(library.exports) 404 ..addAll(library.exports)
390 ..sort((a, b) { 405 ..sort((a, b) {
391 // dart: imports don't have a uri 406 // dart: imports don't have a uri
392 if (a.uri == null && b.uri != null) return -1; 407 if (a.uri == null && b.uri != null) return -1;
393 if (b.uri == null && a.uri != null) return 1; 408 if (b.uri == null && a.uri != null) return 1;
394 if (a.uri == null && b.uri == null) { 409 if (a.uri == null && b.uri == null) {
395 return getLibrary(a).name.compareTo(getLibrary(b).name); 410 return getLibrary(a).name.compareTo(getLibrary(b).name);
396 } 411 }
397 412
398 // package: imports next 413 // package: imports next
399 var aIsPackage = a.uri.startsWith('package:'); 414 var aIsPackage = a.uri.startsWith('package:');
400 var bIsPackage = b.uri.startsWith('package:'); 415 var bIsPackage = b.uri.startsWith('package:');
401 if (aIsPackage && !bIsPackage) { 416 if (aIsPackage && !bIsPackage) {
402 return -1; 417 return -1;
403 } else if (bIsPackage && !aIsPackage) { 418 } else if (bIsPackage && !aIsPackage) {
404 return 1; 419 return 1;
405 } else if (bIsPackage && aIsPackage) { 420 } else if (bIsPackage && aIsPackage) {
406 return a.uri.compareTo(b.uri); 421 return a.uri.compareTo(b.uri);
407 } 422 }
408 423
409 // And finally compare based on the relative uri if both are file paths. 424 // And finally compare based on the relative uri if both are file paths.
410 var aUri = path.url.relative(a.source.uri.path, 425 var aUri = path.url.relative(a.source.uri.path,
411 from: path.url.dirname(library.source.uri.path)); 426 from: path.url.dirname(library.source.uri.path));
412 var bUri = path.url.relative(b.source.uri.path, 427 var bUri = path.url.relative(b.source.uri.path,
413 from: path.url.dirname(library.source.uri.path)); 428 from: path.url.dirname(library.source.uri.path));
414 return aUri.compareTo(bUri); 429 return aUri.compareTo(bUri);
415 })).map(getLibrary); 430 })).map(getLibrary);
416 } 431 }
417 } 432 }
418 433
419 /// An [Initializer] annotation and the target of that annotation. 434 /// An [Initializer] annotation and the target of that annotation.
420 class InitializerData { 435 class InitializerData {
421 /// The target [Element] of the annotation. 436 /// The target [AstNode] of the annotation.
422 final Element targetElement; 437 final AstNode targetNode;
438
439 /// The [Annotation] representing the annotation itself.
440 final Annotation annotationNode;
423 441
424 /// The [ElementAnnotation] representing the annotation itself. 442 /// The [ElementAnnotation] representing the annotation itself.
425 final ElementAnnotation annotationElement; 443 ElementAnnotation get annotationElement => annotationNode.elementAnnotation;
426 444
427 AstNode _targetNode; 445 /// The target [Element] of the annotation.
428 446 Element get targetElement {
429 /// The target [AstNode] of the annotation.
430 // TODO(jakemac): We at least cache this for now, but ideally `targetElement`
431 // would actually be the getter, and `targetNode` would be the property.
432 AstNode get targetNode {
433 if (_targetNode == null) _targetNode = targetElement.node;
434 return _targetNode;
435 }
436
437 /// The [Annotation] representing the annotation itself.
438 Annotation get annotationNode {
439 var annotatedNode;
440 if (targetNode is SimpleIdentifier && 447 if (targetNode is SimpleIdentifier &&
441 targetNode.parent is LibraryIdentifier) { 448 targetNode.parent is LibraryIdentifier) {
442 annotatedNode = targetNode.parent.parent; 449 return targetNode.parent.parent.element;
443 } else if (targetNode is ClassDeclaration || 450 } else if (targetNode is ClassDeclaration ||
444 targetNode is FunctionDeclaration) { 451 targetNode is FunctionDeclaration) {
445 annotatedNode = targetNode; 452 return targetNode.element;
446 } else { 453 } else {
447 return null; 454 return null;
448 } 455 }
449 if (annotatedNode is! AnnotatedNode) return null;
450 var astMeta = annotatedNode.metadata;
451
452 return astMeta.firstWhere((m) => m.elementAnnotation == annotationElement);
453 } 456 }
454 457
455 InitializerData._(this.targetElement, this.annotationElement); 458 InitializerData._(this.targetNode, this.annotationNode);
456 } 459 }
457 460
458 // Reads a file list from a barback settings configuration field. 461 // Reads a file list from a barback settings configuration field.
459 _readFileList(BarbackSettings settings, String field) { 462 _readFileList(BarbackSettings settings, String field) {
460 var value = settings.configuration[field]; 463 var value = settings.configuration[field];
461 if (value == null) return null; 464 if (value == null) return null;
462 var files = []; 465 var files = [];
463 bool error; 466 bool error;
464 if (value is List) { 467 if (value is List) {
465 files = value; 468 files = value;
466 error = value.any((e) => e is! String); 469 error = value.any((e) => e is! String);
467 } else if (value is String) { 470 } else if (value is String) {
468 files = [value]; 471 files = [value];
469 error = false; 472 error = false;
470 } else { 473 } else {
471 error = true; 474 error = true;
472 } 475 }
473 if (error) { 476 if (error) {
474 print('Bad value for "$field" in the initialize transformer. ' 477 print('Bad value for "$field" in the initialize transformer. '
475 'Expected either one String or a list of Strings.'); 478 'Expected either one String or a list of Strings.');
476 } 479 }
477 return files; 480 return files;
478 } 481 }
OLDNEW
« no previous file with comments | « lib/src/mirror_loader.dart ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698