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 |