Index: pkg/analyzer/tool/task_dependency_graph.dart |
diff --git a/pkg/analyzer/tool/task_dependency_graph.dart b/pkg/analyzer/tool/task_dependency_graph.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0d2f2d398c94e358bbded20f01baa34ff65b26cf |
--- /dev/null |
+++ b/pkg/analyzer/tool/task_dependency_graph.dart |
@@ -0,0 +1,150 @@ |
+// Copyright (c) 2015, 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. |
+ |
+/** |
+ * This file contains code to output a description of tasks and their |
+ * dependencies in ".dot" format. Prior to running, the user should run "pub |
+ * get" in the analyzer directory to ensure that a "packages" folder exists. |
+ * |
+ * The ".dot" file is output to standard out. To convert it to a pdf, store it |
+ * in a file (e.g. "tasks.dot"), and post-process it with |
+ * "dot tasks.dart -Tpdf -O". |
+ * |
+ * TODO(paulberry): |
+ * - Add general.dart and html.dart for completeness. |
+ * - Use Graphviz's "record" feature to produce more compact output |
+ * (http://www.graphviz.org/content/node-shapes#record) |
+ * - Produce a warning if a result descriptor is found which isn't the output |
+ * of exactly one task. |
Brian Wilkerson
2015/07/13 15:01:19
One more todo: convert this to use package_config
|
+ */ |
+library task_dependency_graph; |
+ |
+import 'dart:io' hide File; |
+ |
+import 'package:analyzer/analyzer.dart'; |
+import 'package:analyzer/file_system/file_system.dart'; |
+import 'package:analyzer/file_system/physical_file_system.dart'; |
+import 'package:analyzer/src/generated/element.dart'; |
+import 'package:analyzer/src/generated/engine.dart'; |
+import 'package:analyzer/src/generated/java_io.dart'; |
+import 'package:analyzer/src/generated/sdk.dart'; |
+import 'package:analyzer/src/generated/sdk_io.dart'; |
+import 'package:analyzer/src/generated/source.dart'; |
+import 'package:analyzer/src/generated/source_io.dart'; |
+import 'package:path/path.dart' as path; |
+ |
+main() { |
+ new Driver().run(); |
+} |
+ |
+typedef void ResultDescriptorFinderCallback(PropertyAccessorElement element); |
+ |
+class Driver { |
+ PhysicalResourceProvider resourceProvider; |
+ AnalysisContext context; |
+ InterfaceType resultDescriptorType; |
+ String rootDir; |
+ |
+ void findResultDescriptors( |
+ AstNode node, void callback(String descriptorName)) { |
+ Set<PropertyAccessorElement> resultDescriptors = |
+ new Set<PropertyAccessorElement>(); |
+ node.accept(new ResultDescriptorFinder( |
+ resultDescriptorType, resultDescriptors.add)); |
+ for (PropertyAccessorElement resultDescriptor in resultDescriptors) { |
+ callback(resultDescriptor.name); |
+ } |
+ } |
+ |
+ /** |
+ * Find the root directory of the analyzer package by proceeding |
+ * upward to the 'tool' dir, and then going up one more directory. |
+ */ |
+ String findRoot(String pathname) { |
+ while (path.basename(pathname) != 'tool') { |
+ String parent = path.dirname(pathname); |
+ if (parent.length >= pathname.length) { |
+ throw new Exception("Can't find root directory"); |
+ } |
+ pathname = parent; |
+ } |
+ return path.dirname(pathname); |
+ } |
+ |
+ CompilationUnit getUnit(Source source) => |
+ context.resolveCompilationUnit2(source, source); |
+ |
+ void run() { |
+ rootDir = findRoot(Platform.script.toFilePath(windows: Platform.isWindows)); |
+ resourceProvider = PhysicalResourceProvider.INSTANCE; |
+ DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; |
+ context = AnalysisEngine.instance.createAnalysisContext(); |
+ JavaFile packagesDir = new JavaFile(path.join(rootDir, 'packages')); |
+ List<UriResolver> uriResolvers = [ |
+ new FileUriResolver(), |
+ new DartUriResolver(sdk), |
+ new PackageUriResolver(<JavaFile>[packagesDir]) |
+ ]; |
+ context.sourceFactory = new SourceFactory(uriResolvers); |
+ Source taskSource = |
+ setupSource(path.join('lib', 'src', 'task', 'dart.dart')); |
+ Source modelSource = setupSource(path.join('lib', 'task', 'model.dart')); |
+ CompilationUnitElement modelElement = getUnit(modelSource).element; |
+ InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type; |
+ DartType dynamicType = context.typeProvider.dynamicType; |
+ resultDescriptorType = modelElement.getType('ResultDescriptor').type |
+ .substitute4([dynamicType]); |
+ CompilationUnit taskUnit = getUnit(taskSource); |
+ CompilationUnitElement taskUnitElement = taskUnit.element; |
+ print('digraph G {'); |
+ Set<String> results = new Set<String>(); |
+ for (ClassElement cls in taskUnitElement.types) { |
+ if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) { |
+ String task = cls.name; |
+ // TODO(paulberry): node is deprecated. What am I supposed to do |
+ // instead? |
+ findResultDescriptors(cls.getMethod('buildInputs').node, |
+ (String input) { |
+ results.add(input); |
+ print(' $input -> $task'); |
+ }); |
+ findResultDescriptors(cls.getField('DESCRIPTOR').node, (String output) { |
+ results.add(output); |
+ print(' $task -> $output'); |
+ }); |
+ } |
+ } |
+ for (String result in results) { |
+ print(' $result [shape=box]'); |
+ } |
+ print('}'); |
+ } |
+ |
+ Source setupSource(String filename) { |
+ String filePath = path.join(rootDir, filename); |
+ File file = resourceProvider.getResource(filePath); |
+ Source source = file.createSource(); |
+ ChangeSet changeSet = new ChangeSet(); |
+ changeSet.addedSource(source); |
+ context.applyChanges(changeSet); |
+ return source; |
+ } |
+} |
+ |
+class ResultDescriptorFinder extends GeneralizingAstVisitor { |
+ final InterfaceType resultDescriptorType; |
+ final ResultDescriptorFinderCallback callback; |
+ |
+ ResultDescriptorFinder(this.resultDescriptorType, this.callback); |
+ |
+ @override |
+ visitIdentifier(Identifier node) { |
+ Element element = node.staticElement; |
+ if (element is PropertyAccessorElement && |
+ element.isGetter && |
+ element.returnType.isSubtypeOf(resultDescriptorType)) { |
+ callback(element); |
+ } |
+ } |
+} |