| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 | 6 |
| 7 import 'package:analyzer/dart/ast/ast.dart'; | 7 import 'package:front_end/compiler_options.dart'; |
| 8 import 'package:analyzer/error/listener.dart'; | |
| 9 import 'package:analyzer/src/dart/scanner/reader.dart'; | |
| 10 import 'package:analyzer/src/generated/parser.dart'; | |
| 11 import 'package:front_end/file_system.dart'; | |
| 12 import 'package:front_end/src/async_dependency_walker.dart'; | |
| 13 import 'package:front_end/src/base/processed_options.dart'; | 8 import 'package:front_end/src/base/processed_options.dart'; |
| 14 import 'package:front_end/src/base/uri_resolver.dart'; | 9 import 'package:front_end/src/dependency_grapher_impl.dart' as impl; |
| 15 import 'package:front_end/src/scanner/scanner.dart'; | |
| 16 | |
| 17 import 'compiler_options.dart'; | |
| 18 | 10 |
| 19 /// Generates a representation of the dependency graph of a program. | 11 /// Generates a representation of the dependency graph of a program. |
| 20 /// | 12 /// |
| 21 /// Given the Uri of one or more files, this function follows `import`, | 13 /// Given the Uri of one or more files, this function follows `import`, |
| 22 /// `export`, and `part` declarations to discover a graph of all files involved | 14 /// `export`, and `part` declarations to discover a graph of all files involved |
| 23 /// in the program. | 15 /// in the program. |
| 24 Future<Graph> graphForProgram( | 16 Future<Graph> graphForProgram(List<Uri> sources, CompilerOptions options) { |
| 25 List<Uri> sources, CompilerOptions options) async { | |
| 26 var processedOptions = new ProcessedOptions(options); | 17 var processedOptions = new ProcessedOptions(options); |
| 27 var uriResolver = await processedOptions.getUriResolver(); | 18 return impl.graphForProgram(sources, processedOptions); |
| 28 var walker = new _Walker(processedOptions.fileSystem, uriResolver, processedOp
tions.compileSdk); | |
| 29 var startingPoint = new _StartingPoint(walker, sources); | |
| 30 await walker.walk(startingPoint); | |
| 31 return walker.graph; | |
| 32 } | 19 } |
| 33 | 20 |
| 34 /// A representation of the dependency graph of a program. | 21 /// A representation of the dependency graph of a program. |
| 35 /// | 22 /// |
| 36 /// Not intended to be extended, implemented, or mixed in by clients. | 23 /// Not intended to be extended, implemented, or mixed in by clients. |
| 37 class Graph { | 24 class Graph { |
| 38 /// A list of all library cycles in the program, in topologically sorted order | 25 /// A list of all library cycles in the program, in topologically sorted order |
| 39 /// (each cycle only depends on libraries in the cycles that precede it). | 26 /// (each cycle only depends on libraries in the cycles that precede it). |
| 40 final topologicallySortedCycles = <LibraryCycleNode>[]; | 27 final topologicallySortedCycles = <LibraryCycleNode>[]; |
| 41 | |
| 42 Graph._(); | |
| 43 } | 28 } |
| 44 | 29 |
| 45 /// A representation of a single library cycle in the dependency graph of a | 30 /// A representation of a single library cycle in the dependency graph of a |
| 46 /// program. | 31 /// program. |
| 47 /// | 32 /// |
| 48 /// Not intended to be extended, implemented, or mixed in by clients. | 33 /// Not intended to be extended, implemented, or mixed in by clients. |
| 49 class LibraryCycleNode { | 34 class LibraryCycleNode { |
| 50 /// A map of all the libraries in the cycle, keyed by the URI of their | 35 /// A map of all the libraries in the cycle, keyed by the URI of their |
| 51 /// defining compilation unit. | 36 /// defining compilation unit. |
| 52 final libraries = <Uri, LibraryNode>{}; | 37 final libraries = <Uri, LibraryNode>{}; |
| 53 | |
| 54 LibraryCycleNode._(); | |
| 55 } | 38 } |
| 56 | 39 |
| 57 /// A representation of a single library in the dependency graph of a program. | 40 /// A representation of a single library in the dependency graph of a program. |
| 58 /// | 41 /// |
| 59 /// Not intended to be extended, implemented, or mixed in by clients. | 42 /// Not intended to be extended, implemented, or mixed in by clients. |
| 60 class LibraryNode { | 43 class LibraryNode { |
| 61 /// The URI of this library's defining compilation unit. | 44 /// The URI of this library's defining compilation unit. |
| 62 final Uri uri; | 45 final Uri uri; |
| 63 | 46 |
| 64 /// A list of the URIs of all of this library's "part" files. | 47 /// A list of the URIs of all of this library's "part" files. |
| 65 final parts = <Uri>[]; | 48 final parts = <Uri>[]; |
| 66 | 49 |
| 67 /// A list of all the other libraries this library directly depends on. | 50 /// A list of all the other libraries this library directly depends on. |
| 68 final dependencies = <LibraryNode>[]; | 51 final dependencies = <LibraryNode>[]; |
| 69 | 52 |
| 70 LibraryNode._(this.uri); | 53 LibraryNode(this.uri); |
| 71 } | 54 } |
| 72 | |
| 73 class _Scanner extends Scanner { | |
| 74 _Scanner(String contents) : super(new CharSequenceReader(contents)) { | |
| 75 preserveComments = false; | |
| 76 } | |
| 77 | |
| 78 @override | |
| 79 void reportError(errorCode, int offset, List<Object> arguments) { | |
| 80 // TODO(paulberry): report errors. | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 class _StartingPoint extends _WalkerNode { | |
| 85 final List<Uri> sources; | |
| 86 | |
| 87 _StartingPoint(_Walker walker, this.sources) : super(walker, null); | |
| 88 | |
| 89 @override | |
| 90 Future<List<_WalkerNode>> computeDependencies() async => | |
| 91 sources.map(walker.nodeForUri).toList(); | |
| 92 } | |
| 93 | |
| 94 class _Walker extends AsyncDependencyWalker<_WalkerNode> { | |
| 95 final FileSystem fileSystem; | |
| 96 final UriResolver uriResolver; | |
| 97 final _nodesByUri = <Uri, _WalkerNode>{}; | |
| 98 final graph = new Graph._(); | |
| 99 final bool compileSdk; | |
| 100 | |
| 101 _Walker(this.fileSystem, this.uriResolver, this.compileSdk); | |
| 102 | |
| 103 @override | |
| 104 Future<Null> evaluate(_WalkerNode v) { | |
| 105 if (v is _StartingPoint) return new Future.value(); | |
| 106 return evaluateScc([v]); | |
| 107 } | |
| 108 | |
| 109 @override | |
| 110 Future<Null> evaluateScc(List<_WalkerNode> scc) { | |
| 111 var cycle = new LibraryCycleNode._(); | |
| 112 for (var walkerNode in scc) { | |
| 113 cycle.libraries[walkerNode.uri] = walkerNode.library; | |
| 114 } | |
| 115 graph.topologicallySortedCycles.add(cycle); | |
| 116 return new Future.value(); | |
| 117 } | |
| 118 | |
| 119 _WalkerNode nodeForUri(Uri referencedUri) { | |
| 120 var dependencyNode = _nodesByUri.putIfAbsent( | |
| 121 referencedUri, () => new _WalkerNode(this, referencedUri)); | |
| 122 return dependencyNode; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 class _WalkerNode extends Node<_WalkerNode> { | |
| 127 static final dartCoreUri = Uri.parse('dart:core'); | |
| 128 final _Walker walker; | |
| 129 final Uri uri; | |
| 130 final LibraryNode library; | |
| 131 | |
| 132 _WalkerNode(this.walker, Uri uri) | |
| 133 : uri = uri, | |
| 134 library = new LibraryNode._(uri); | |
| 135 | |
| 136 @override | |
| 137 Future<List<_WalkerNode>> computeDependencies() async { | |
| 138 var dependencies = <_WalkerNode>[]; | |
| 139 // TODO(paulberry): add error recovery if the file can't be read. | |
| 140 var path = walker.uriResolver.resolve(uri); | |
| 141 if (path == null) { | |
| 142 // TODO(paulberry): If an error reporter was provided, report the error | |
| 143 // in the proper way and continue. | |
| 144 throw new StateError('Invalid URI: $uri'); | |
| 145 } | |
| 146 var contents = await walker.fileSystem.entityForPath(path).readAsString(); | |
| 147 var scanner = new _Scanner(contents); | |
| 148 var token = scanner.tokenize(); | |
| 149 // TODO(paulberry): report errors. | |
| 150 var parser = new Parser(null, AnalysisErrorListener.NULL_LISTENER); | |
| 151 var unit = parser.parseDirectives(token); | |
| 152 bool coreUriFound = false; | |
| 153 void handleDependency(Uri referencedUri) { | |
| 154 _WalkerNode dependencyNode = walker.nodeForUri(referencedUri); | |
| 155 library.dependencies.add(dependencyNode.library); | |
| 156 if (referencedUri.scheme != 'dart' || walker.compileSdk) { | |
| 157 dependencies.add(dependencyNode); | |
| 158 } | |
| 159 if (referencedUri == dartCoreUri) { | |
| 160 coreUriFound = true; | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 for (var directive in unit.directives) { | |
| 165 if (directive is UriBasedDirective) { | |
| 166 // TODO(paulberry): when we support SDK libraries, we'll need more | |
| 167 // complex logic here to find SDK parts correctly. | |
| 168 var referencedUri = uri.resolve(directive.uri.stringValue); | |
| 169 if (directive is PartDirective) { | |
| 170 library.parts.add(referencedUri); | |
| 171 } else { | |
| 172 handleDependency(referencedUri); | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 if (!coreUriFound) { | |
| 177 handleDependency(dartCoreUri); | |
| 178 } | |
| 179 return dependencies; | |
| 180 } | |
| 181 } | |
| OLD | NEW |