OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * This file contains code to output a description of tasks and their |
| 7 * dependencies in ".dot" format. Prior to running, the user should run "pub |
| 8 * get" in the analyzer directory to ensure that a "packages" folder exists. |
| 9 * |
| 10 * The ".dot" file is output to standard out. To convert it to a pdf, store it |
| 11 * in a file (e.g. "tasks.dot"), and post-process it with |
| 12 * "dot tasks.dart -Tpdf -O". |
| 13 * |
| 14 * TODO(paulberry): |
| 15 * - Add general.dart and html.dart for completeness. |
| 16 * - Use Graphviz's "record" feature to produce more compact output |
| 17 * (http://www.graphviz.org/content/node-shapes#record) |
| 18 * - Produce a warning if a result descriptor is found which isn't the output |
| 19 * of exactly one task. |
| 20 * - Convert this tool to use package_config to find the package map. |
| 21 */ |
| 22 library task_dependency_graph; |
| 23 |
| 24 import 'dart:io' hide File; |
| 25 |
| 26 import 'package:analyzer/analyzer.dart'; |
| 27 import 'package:analyzer/file_system/file_system.dart'; |
| 28 import 'package:analyzer/file_system/physical_file_system.dart'; |
| 29 import 'package:analyzer/src/generated/element.dart'; |
| 30 import 'package:analyzer/src/generated/engine.dart'; |
| 31 import 'package:analyzer/src/generated/java_io.dart'; |
| 32 import 'package:analyzer/src/generated/sdk.dart'; |
| 33 import 'package:analyzer/src/generated/sdk_io.dart'; |
| 34 import 'package:analyzer/src/generated/source.dart'; |
| 35 import 'package:analyzer/src/generated/source_io.dart'; |
| 36 import 'package:path/path.dart' as path; |
| 37 |
| 38 main() { |
| 39 new Driver().run(); |
| 40 } |
| 41 |
| 42 typedef void ResultDescriptorFinderCallback(PropertyAccessorElement element); |
| 43 |
| 44 class Driver { |
| 45 PhysicalResourceProvider resourceProvider; |
| 46 AnalysisContext context; |
| 47 InterfaceType resultDescriptorType; |
| 48 String rootDir; |
| 49 |
| 50 void findResultDescriptors( |
| 51 AstNode node, void callback(String descriptorName)) { |
| 52 Set<PropertyAccessorElement> resultDescriptors = |
| 53 new Set<PropertyAccessorElement>(); |
| 54 node.accept(new ResultDescriptorFinder( |
| 55 resultDescriptorType, resultDescriptors.add)); |
| 56 for (PropertyAccessorElement resultDescriptor in resultDescriptors) { |
| 57 callback(resultDescriptor.name); |
| 58 } |
| 59 } |
| 60 |
| 61 /** |
| 62 * Find the root directory of the analyzer package by proceeding |
| 63 * upward to the 'tool' dir, and then going up one more directory. |
| 64 */ |
| 65 String findRoot(String pathname) { |
| 66 while (path.basename(pathname) != 'tool') { |
| 67 String parent = path.dirname(pathname); |
| 68 if (parent.length >= pathname.length) { |
| 69 throw new Exception("Can't find root directory"); |
| 70 } |
| 71 pathname = parent; |
| 72 } |
| 73 return path.dirname(pathname); |
| 74 } |
| 75 |
| 76 CompilationUnit getUnit(Source source) => |
| 77 context.resolveCompilationUnit2(source, source); |
| 78 |
| 79 void run() { |
| 80 rootDir = findRoot(Platform.script.toFilePath(windows: Platform.isWindows)); |
| 81 resourceProvider = PhysicalResourceProvider.INSTANCE; |
| 82 DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; |
| 83 context = AnalysisEngine.instance.createAnalysisContext(); |
| 84 JavaFile packagesDir = new JavaFile(path.join(rootDir, 'packages')); |
| 85 List<UriResolver> uriResolvers = [ |
| 86 new DartUriResolver(sdk), |
| 87 new PackageUriResolver(<JavaFile>[packagesDir]), |
| 88 new FileUriResolver() |
| 89 ]; |
| 90 context.sourceFactory = new SourceFactory(uriResolvers); |
| 91 Source taskSource = |
| 92 setupSource(path.join('lib', 'src', 'task', 'dart.dart')); |
| 93 Source modelSource = setupSource(path.join('lib', 'task', 'model.dart')); |
| 94 CompilationUnitElement modelElement = getUnit(modelSource).element; |
| 95 InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type; |
| 96 DartType dynamicType = context.typeProvider.dynamicType; |
| 97 resultDescriptorType = modelElement |
| 98 .getType('ResultDescriptor') |
| 99 .type |
| 100 .substitute4([dynamicType]); |
| 101 CompilationUnit taskUnit = getUnit(taskSource); |
| 102 CompilationUnitElement taskUnitElement = taskUnit.element; |
| 103 print('digraph G {'); |
| 104 Set<String> results = new Set<String>(); |
| 105 for (ClassElement cls in taskUnitElement.types) { |
| 106 if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) { |
| 107 String task = cls.name; |
| 108 // TODO(paulberry): node is deprecated. What am I supposed to do |
| 109 // instead? |
| 110 findResultDescriptors(cls.getMethod('buildInputs').node, |
| 111 (String input) { |
| 112 results.add(input); |
| 113 print(' $input -> $task'); |
| 114 }); |
| 115 findResultDescriptors(cls.getField('DESCRIPTOR').node, (String output) { |
| 116 results.add(output); |
| 117 print(' $task -> $output'); |
| 118 }); |
| 119 } |
| 120 } |
| 121 for (String result in results) { |
| 122 print(' $result [shape=box]'); |
| 123 } |
| 124 print('}'); |
| 125 } |
| 126 |
| 127 Source setupSource(String filename) { |
| 128 String filePath = path.join(rootDir, filename); |
| 129 File file = resourceProvider.getResource(filePath); |
| 130 Source source = file.createSource(); |
| 131 Uri restoredUri = context.sourceFactory.restoreUri(source); |
| 132 if (restoredUri != null) { |
| 133 source = file.createSource(restoredUri); |
| 134 } |
| 135 ChangeSet changeSet = new ChangeSet(); |
| 136 changeSet.addedSource(source); |
| 137 context.applyChanges(changeSet); |
| 138 return source; |
| 139 } |
| 140 } |
| 141 |
| 142 class ResultDescriptorFinder extends GeneralizingAstVisitor { |
| 143 final InterfaceType resultDescriptorType; |
| 144 final ResultDescriptorFinderCallback callback; |
| 145 |
| 146 ResultDescriptorFinder(this.resultDescriptorType, this.callback); |
| 147 |
| 148 @override |
| 149 visitIdentifier(Identifier node) { |
| 150 Element element = node.staticElement; |
| 151 if (element is PropertyAccessorElement && |
| 152 element.isGetter && |
| 153 element.returnType.isSubtypeOf(resultDescriptorType)) { |
| 154 callback(element); |
| 155 } |
| 156 } |
| 157 } |
OLD | NEW |