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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: pkg/front_end/lib/dependency_grapher.dart
diff --git a/pkg/front_end/lib/dependency_grapher.dart b/pkg/front_end/lib/dependency_grapher.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b256a78e7db77c0abeffeb74a625f143a64be842
--- /dev/null
+++ b/pkg/front_end/lib/dependency_grapher.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:front_end/file_system.dart';
+import 'package:front_end/src/async_dependency_walker.dart';
+import 'package:front_end/src/base/uri_resolver.dart';
+import 'package:front_end/src/scanner/scanner.dart';
+
+import 'compiler_options.dart';
+
+/// Generates a representation of the dependency graph of a program.
+///
+/// Given the Uri of one or more files, this function follows `import`,
+/// `export`, and `part` declarations to discover a graph of all files involved
+/// in the program.
+Future<Graph> graphForProgram(
+ List<Uri> sources, CompilerOptions options) async {
+ 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
+ var sdkLibraries = <String, Uri>{}; // TODO(paulberry): support SDK libraries
+ var uriResolver =
+ new UriResolver(packages, sdkLibraries, options.fileSystem.context);
+ var walker = new _Walker(options.fileSystem, uriResolver);
+ var startingPoint = new _StartingPoint(walker, sources);
+ await walker.walk(startingPoint);
+ return walker.graph;
+}
+
+/// A representation of the dependency graph of a program.
+///
+/// Not intended to be extended, implemented, or mixed in by clients.
+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.
+ /// A list of all library cycles in the program, in topologically sorted order
+ /// (each cycle only depends on libraries in the cycles that precede it).
+ final topologicallySortedCycles = <LibraryCycleNode>[];
+
+ Graph._();
+}
+
+/// A representation of a single library cycle in the dependency graph of a
+/// program.
+///
+/// Not intended to be extended, implemented, or mixed in by clients.
+class LibraryCycleNode {
+ /// 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.
+ /// defining compilation unit.
+ final libraries = <Uri, LibraryNode>{};
+
+ LibraryCycleNode._();
+}
+
+/// A representation of a single library in the dependency graph of a program.
+///
+/// Not intended to be extended, implemented, or mixed in by clients.
+class LibraryNode {
+ /// A list of all the other libraries this library directly depends on.
+ 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
+
+ /// A list of the URIs of all of this library's "part" files.
+ final parts = <Uri>[];
+
+ /// 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.
+ final Uri uri;
+
+ LibraryNode._(this.uri);
+}
+
+class _Scanner extends Scanner {
+ _Scanner(String contents) : super(new CharSequenceReader(contents)) {
+ preserveComments = false;
+ }
+
+ @override
+ void reportError(errorCode, int offset, List<Object> arguments) {
+ // TODO(paulberry): report errors.
+ }
+}
+
+class _StartingPoint extends _WalkerNode {
+ final List<Uri> sources;
+
+ _StartingPoint(_Walker walker, this.sources) : super(walker, null);
+
+ @override
+ Future<List<_WalkerNode>> computeDependencies() async =>
+ sources.map(walker.nodeForUri).toList();
+}
+
+class _Walker extends AsyncDependencyWalker<_WalkerNode> {
+ final FileSystem fileSystem;
+ final UriResolver uriResolver;
+ final _nodesByUri = <Uri, _WalkerNode>{};
+ final graph = new Graph._();
+
+ _Walker(this.fileSystem, this.uriResolver);
+
+ @override
+ Future<Null> evaluate(_WalkerNode v) {
+ if (v is _StartingPoint) return new Future.value();
+ return evaluateScc([v]);
+ }
+
+ @override
+ Future<Null> evaluateScc(List<_WalkerNode> scc) {
+ var cycle = new LibraryCycleNode._();
+ for (var walkerNode in scc) {
+ cycle.libraries[walkerNode.uri] = walkerNode.library;
+ }
+ graph.topologicallySortedCycles.add(cycle);
+ return new Future.value();
+ }
+
+ _WalkerNode nodeForUri(Uri referencedUri) {
+ var dependencyNode = _nodesByUri.putIfAbsent(
+ referencedUri, () => new _WalkerNode(this, referencedUri));
+ return dependencyNode;
+ }
+}
+
+class _WalkerNode extends Node<_WalkerNode> {
+ final _Walker walker;
+ final Uri uri;
+ final LibraryNode library;
+
+ _WalkerNode(this.walker, Uri uri)
+ : uri = uri,
+ library = new LibraryNode._(uri);
+
+ @override
+ Future<List<_WalkerNode>> computeDependencies() async {
+ var dependencies = <_WalkerNode>[];
+ // TODO(paulberry): add error recovery if the file can't be read.
+ var contents = await walker.fileSystem
+ .entityForPath(walker.uriResolver.resolve(uri))
+ .readAsString();
+ var scanner = new _Scanner(contents);
+ var token = scanner.tokenize();
+ // TODO(paulberry): report errors.
+ var parser = new Parser(null, AnalysisErrorListener.NULL_LISTENER);
+ 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.
+ for (var directive in unit.directives) {
+ if (directive is UriBasedDirective) {
+ // TODO(paulberry): when we support SDK libraries, we'll need more
+ // complex logic here to find SDK parts correctly.
+ var referencedUri = uri.resolve(directive.uri.stringValue);
+ if (directive is PartDirective) {
+ library.parts.add(referencedUri);
+ } else {
+ _WalkerNode dependencyNode = walker.nodeForUri(referencedUri);
+ dependencies.add(dependencyNode);
+ library.dependencies.add(dependencyNode.library);
+ }
+ }
+ }
+ return dependencies;
+ }
+}
« 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