Chromium Code Reviews| 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. | |
|
Brian Wilkerson
2015/07/13 15:01:19
One more todo: convert this to use package_config
| |
| 20 */ | |
| 21 library task_dependency_graph; | |
| 22 | |
| 23 import 'dart:io' hide File; | |
| 24 | |
| 25 import 'package:analyzer/analyzer.dart'; | |
| 26 import 'package:analyzer/file_system/file_system.dart'; | |
| 27 import 'package:analyzer/file_system/physical_file_system.dart'; | |
| 28 import 'package:analyzer/src/generated/element.dart'; | |
| 29 import 'package:analyzer/src/generated/engine.dart'; | |
| 30 import 'package:analyzer/src/generated/java_io.dart'; | |
| 31 import 'package:analyzer/src/generated/sdk.dart'; | |
| 32 import 'package:analyzer/src/generated/sdk_io.dart'; | |
| 33 import 'package:analyzer/src/generated/source.dart'; | |
| 34 import 'package:analyzer/src/generated/source_io.dart'; | |
| 35 import 'package:path/path.dart' as path; | |
| 36 | |
| 37 main() { | |
| 38 new Driver().run(); | |
| 39 } | |
| 40 | |
| 41 typedef void ResultDescriptorFinderCallback(PropertyAccessorElement element); | |
| 42 | |
| 43 class Driver { | |
| 44 PhysicalResourceProvider resourceProvider; | |
| 45 AnalysisContext context; | |
| 46 InterfaceType resultDescriptorType; | |
| 47 String rootDir; | |
| 48 | |
| 49 void findResultDescriptors( | |
| 50 AstNode node, void callback(String descriptorName)) { | |
| 51 Set<PropertyAccessorElement> resultDescriptors = | |
| 52 new Set<PropertyAccessorElement>(); | |
| 53 node.accept(new ResultDescriptorFinder( | |
| 54 resultDescriptorType, resultDescriptors.add)); | |
| 55 for (PropertyAccessorElement resultDescriptor in resultDescriptors) { | |
| 56 callback(resultDescriptor.name); | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 /** | |
| 61 * Find the root directory of the analyzer package by proceeding | |
| 62 * upward to the 'tool' dir, and then going up one more directory. | |
| 63 */ | |
| 64 String findRoot(String pathname) { | |
| 65 while (path.basename(pathname) != 'tool') { | |
| 66 String parent = path.dirname(pathname); | |
| 67 if (parent.length >= pathname.length) { | |
| 68 throw new Exception("Can't find root directory"); | |
| 69 } | |
| 70 pathname = parent; | |
| 71 } | |
| 72 return path.dirname(pathname); | |
| 73 } | |
| 74 | |
| 75 CompilationUnit getUnit(Source source) => | |
| 76 context.resolveCompilationUnit2(source, source); | |
| 77 | |
| 78 void run() { | |
| 79 rootDir = findRoot(Platform.script.toFilePath(windows: Platform.isWindows)); | |
| 80 resourceProvider = PhysicalResourceProvider.INSTANCE; | |
| 81 DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; | |
| 82 context = AnalysisEngine.instance.createAnalysisContext(); | |
| 83 JavaFile packagesDir = new JavaFile(path.join(rootDir, 'packages')); | |
| 84 List<UriResolver> uriResolvers = [ | |
| 85 new FileUriResolver(), | |
| 86 new DartUriResolver(sdk), | |
| 87 new PackageUriResolver(<JavaFile>[packagesDir]) | |
| 88 ]; | |
| 89 context.sourceFactory = new SourceFactory(uriResolvers); | |
| 90 Source taskSource = | |
| 91 setupSource(path.join('lib', 'src', 'task', 'dart.dart')); | |
| 92 Source modelSource = setupSource(path.join('lib', 'task', 'model.dart')); | |
| 93 CompilationUnitElement modelElement = getUnit(modelSource).element; | |
| 94 InterfaceType analysisTaskType = modelElement.getType('AnalysisTask').type; | |
| 95 DartType dynamicType = context.typeProvider.dynamicType; | |
| 96 resultDescriptorType = modelElement.getType('ResultDescriptor').type | |
| 97 .substitute4([dynamicType]); | |
| 98 CompilationUnit taskUnit = getUnit(taskSource); | |
| 99 CompilationUnitElement taskUnitElement = taskUnit.element; | |
| 100 print('digraph G {'); | |
| 101 Set<String> results = new Set<String>(); | |
| 102 for (ClassElement cls in taskUnitElement.types) { | |
| 103 if (!cls.isAbstract && cls.type.isSubtypeOf(analysisTaskType)) { | |
| 104 String task = cls.name; | |
| 105 // TODO(paulberry): node is deprecated. What am I supposed to do | |
| 106 // instead? | |
| 107 findResultDescriptors(cls.getMethod('buildInputs').node, | |
| 108 (String input) { | |
| 109 results.add(input); | |
| 110 print(' $input -> $task'); | |
| 111 }); | |
| 112 findResultDescriptors(cls.getField('DESCRIPTOR').node, (String output) { | |
| 113 results.add(output); | |
| 114 print(' $task -> $output'); | |
| 115 }); | |
| 116 } | |
| 117 } | |
| 118 for (String result in results) { | |
| 119 print(' $result [shape=box]'); | |
| 120 } | |
| 121 print('}'); | |
| 122 } | |
| 123 | |
| 124 Source setupSource(String filename) { | |
| 125 String filePath = path.join(rootDir, filename); | |
| 126 File file = resourceProvider.getResource(filePath); | |
| 127 Source source = file.createSource(); | |
| 128 ChangeSet changeSet = new ChangeSet(); | |
| 129 changeSet.addedSource(source); | |
| 130 context.applyChanges(changeSet); | |
| 131 return source; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 class ResultDescriptorFinder extends GeneralizingAstVisitor { | |
| 136 final InterfaceType resultDescriptorType; | |
| 137 final ResultDescriptorFinderCallback callback; | |
| 138 | |
| 139 ResultDescriptorFinder(this.resultDescriptorType, this.callback); | |
| 140 | |
| 141 @override | |
| 142 visitIdentifier(Identifier node) { | |
| 143 Element element = node.staticElement; | |
| 144 if (element is PropertyAccessorElement && | |
| 145 element.isGetter && | |
| 146 element.returnType.isSubtypeOf(resultDescriptorType)) { | |
| 147 callback(element); | |
| 148 } | |
| 149 } | |
| 150 } | |
| OLD | NEW |