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

Side by Side Diff: pkg/front_end/lib/dependency_grapher.dart

Issue 2575403005: Implement a front end API for querying the dependency structure of a project. (Closed)
Patch Set: Created 4 years 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:async';
6
7 import 'package:analyzer/dart/ast/ast.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/uri_resolver.dart';
14 import 'package:front_end/src/scanner/scanner.dart';
15
16 import 'compiler_options.dart';
17
18 /// Generates a representation of the dependency graph of a program.
19 ///
20 /// Given the Uri of one or more files, this function follows `import`,
21 /// `export`, and `part` declarations to discover a graph of all files involved
22 /// in the program.
23 Future<Graph> graphForProgram(
24 List<Uri> sources, CompilerOptions options) async {
25 var packages = <String, Uri>{}; // TODO(paulberry): support packages
Siggi Cherem (dart-lang) 2016/12/15 23:51:33 should we have a "digested options" at some point
Paul Berry 2016/12/16 02:46:45 Perhaps, I'm not sure yet. I kind of want to fill
26 var sdkLibraries = <String, Uri>{}; // TODO(paulberry): support SDK libraries
27 var uriResolver =
28 new UriResolver(packages, sdkLibraries, options.fileSystem.context);
29 var walker = new _Walker(options.fileSystem, uriResolver);
30 var startingPoint = new _StartingPoint(walker, sources);
31 await walker.walk(startingPoint);
32 return walker.graph;
33 }
34
35 /// A representation of the dependency graph of a program.
36 ///
37 /// Not intended to be extended, implemented, or mixed in by clients.
38 class Graph {
Siggi Cherem (dart-lang) 2016/12/15 23:51:33 as we start looking into integrating alternative i
Paul Berry 2016/12/16 02:46:45 Acknowledged.
39 /// A list of all library cycles in the program, in topologically sorted order
40 /// (each cycle only depends on libraries in the cycles that precede it).
41 final topologicallySortedCycles = <LibraryCycleNode>[];
42
43 Graph._();
44 }
45
46 /// A representation of a single library cycle in the dependency graph of a
47 /// program.
48 ///
49 /// Not intended to be extended, implemented, or mixed in by clients.
50 class LibraryCycleNode {
51 /// A map of all the libraries in the program, keyed by the URI of their
Siggi Cherem (dart-lang) 2016/12/15 23:51:33 all libraries in the program or in the cycle?
Paul Berry 2016/12/16 02:46:45 Whoops, I meant to say "in the cycle". Fixed.
52 /// defining compilation unit.
53 final libraries = <Uri, LibraryNode>{};
54
55 LibraryCycleNode._();
56 }
57
58 /// A representation of a single library in the dependency graph of a program.
59 ///
60 /// Not intended to be extended, implemented, or mixed in by clients.
61 class LibraryNode {
62 /// A list of all the other libraries this library directly depends on.
63 final dependencies = <LibraryNode>[];
Siggi Cherem (dart-lang) 2016/12/15 23:51:33 do we want to split imports and exports or in gene
Paul Berry 2016/12/16 02:46:45 My intuition is no--any client that needs to disti
64
65 /// A list of the URIs of all of this library's "part" files.
66 final parts = <Uri>[];
67
68 /// The URI of this library's defining compilation unit.
Siggi Cherem (dart-lang) 2016/12/15 23:51:33 you may be using an alphabetic order, but I rather
Paul Berry 2016/12/16 02:46:45 Done.
69 final Uri uri;
70
71 LibraryNode._(this.uri);
72 }
73
74 class _Scanner extends Scanner {
75 _Scanner(String contents) : super(new CharSequenceReader(contents)) {
76 preserveComments = false;
77 }
78
79 @override
80 void reportError(errorCode, int offset, List<Object> arguments) {
81 // TODO(paulberry): report errors.
82 }
83 }
84
85 class _StartingPoint extends _WalkerNode {
86 final List<Uri> sources;
87
88 _StartingPoint(_Walker walker, this.sources) : super(walker, null);
89
90 @override
91 Future<List<_WalkerNode>> computeDependencies() async =>
92 sources.map(walker.nodeForUri).toList();
93 }
94
95 class _Walker extends AsyncDependencyWalker<_WalkerNode> {
96 final FileSystem fileSystem;
97 final UriResolver uriResolver;
98 final _nodesByUri = <Uri, _WalkerNode>{};
99 final graph = new Graph._();
100
101 _Walker(this.fileSystem, this.uriResolver);
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 final _Walker walker;
128 final Uri uri;
129 final LibraryNode library;
130
131 _WalkerNode(this.walker, Uri uri)
132 : uri = uri,
133 library = new LibraryNode._(uri);
134
135 @override
136 Future<List<_WalkerNode>> computeDependencies() async {
137 var dependencies = <_WalkerNode>[];
138 // TODO(paulberry): add error recovery if the file can't be read.
139 var contents = await walker.fileSystem
140 .entityForPath(walker.uriResolver.resolve(uri))
141 .readAsString();
142 var scanner = new _Scanner(contents);
143 var token = scanner.tokenize();
144 // TODO(paulberry): report errors.
145 var parser = new Parser(null, AnalysisErrorListener.NULL_LISTENER);
146 var unit = parser.parseDirectives(token);
Siggi Cherem (dart-lang) 2016/12/15 23:51:33 I'm OK delaying this until later to avoid over-eng
Paul Berry 2016/12/16 02:46:45 Acknowledged.
147 for (var directive in unit.directives) {
148 if (directive is UriBasedDirective) {
149 // TODO(paulberry): when we support SDK libraries, we'll need more
150 // complex logic here to find SDK parts correctly.
151 var referencedUri = uri.resolve(directive.uri.stringValue);
152 if (directive is PartDirective) {
153 library.parts.add(referencedUri);
154 } else {
155 _WalkerNode dependencyNode = walker.nodeForUri(referencedUri);
156 dependencies.add(dependencyNode);
157 library.dependencies.add(dependencyNode.library);
158 }
159 }
160 }
161 return dependencies;
162 }
163 }
OLDNEW
« no previous file with comments | « no previous file | pkg/front_end/test/dependency_grapher_test.dart » ('j') | pkg/front_end/test/dependency_grapher_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698