OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * This file contains code to output a description of tasks and their | 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 | 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. | 8 * get" in the analyzer directory to ensure that a "packages" folder exists. |
9 * | 9 * |
10 * TODO(paulberry): | 10 * TODO(paulberry): |
11 * - Add general.dart and html.dart for completeness. | 11 * - Add general.dart and html.dart for completeness. |
12 * - Use Graphviz's "record" feature to produce more compact output | 12 * - Use Graphviz's "record" feature to produce more compact output |
13 * (http://www.graphviz.org/content/node-shapes#record) | 13 * (http://www.graphviz.org/content/node-shapes#record) |
14 * - Produce a warning if a result descriptor is found which isn't the output | 14 * - Produce a warning if a result descriptor is found which isn't the output |
15 * of exactly one task. | 15 * of exactly one task. |
16 * - Convert this tool to use package_config to find the package map. | 16 * - Convert this tool to use package_config to find the package map. |
17 */ | 17 */ |
18 library task_dependency_graph.generate; | 18 library task_dependency_graph.generate; |
19 | 19 |
20 import 'dart:io' hide File; | 20 import 'dart:io' hide File; |
21 import 'dart:io' as io; | 21 import 'dart:io' as io; |
22 | 22 |
23 import 'package:analyzer/analyzer.dart'; | 23 import 'package:analyzer/analyzer.dart'; |
24 import 'package:analyzer/file_system/file_system.dart'; | 24 import 'package:analyzer/file_system/file_system.dart'; |
25 import 'package:analyzer/file_system/physical_file_system.dart'; | 25 import 'package:analyzer/file_system/physical_file_system.dart'; |
| 26 import 'package:analyzer/src/codegen/tools.dart'; |
26 import 'package:analyzer/src/generated/constant.dart'; | 27 import 'package:analyzer/src/generated/constant.dart'; |
27 import 'package:analyzer/src/generated/element.dart'; | 28 import 'package:analyzer/src/generated/element.dart'; |
28 import 'package:analyzer/src/generated/engine.dart'; | 29 import 'package:analyzer/src/generated/engine.dart'; |
29 import 'package:analyzer/src/generated/java_io.dart'; | 30 import 'package:analyzer/src/generated/java_io.dart'; |
30 import 'package:analyzer/src/generated/sdk.dart'; | 31 import 'package:analyzer/src/generated/sdk.dart'; |
31 import 'package:analyzer/src/generated/sdk_io.dart'; | 32 import 'package:analyzer/src/generated/sdk_io.dart'; |
32 import 'package:analyzer/src/generated/source.dart'; | 33 import 'package:analyzer/src/generated/source.dart'; |
33 import 'package:analyzer/src/generated/source_io.dart'; | 34 import 'package:analyzer/src/generated/source_io.dart'; |
34 import 'package:path/path.dart' as path; | 35 import 'package:path/path.dart' as path; |
| 36 import 'package:path/path.dart'; |
35 | 37 |
36 /** | 38 /** |
37 * Generate the target .dot file. | 39 * Generate the target .dot file. |
38 */ | 40 */ |
39 main() { | 41 main() { |
40 new Driver().generateFile(); | 42 String script = Platform.script.toFilePath(windows: Platform.isWindows); |
| 43 String pkgPath = normalize(join(dirname(script), '..', '..')); |
| 44 target.generate(pkgPath); |
41 } | 45 } |
42 | 46 |
| 47 final GeneratedFile target = new GeneratedFile( |
| 48 'tool/task_dependency_graph/tasks.dot', |
| 49 (String pkgPath) => new Driver(pkgPath).generateFileContents()); |
| 50 |
43 typedef void GetterFinderCallback(PropertyAccessorElement element); | 51 typedef void GetterFinderCallback(PropertyAccessorElement element); |
44 | 52 |
45 class Driver { | 53 class Driver { |
46 PhysicalResourceProvider resourceProvider; | 54 PhysicalResourceProvider resourceProvider; |
47 AnalysisContext context; | 55 AnalysisContext context; |
48 InterfaceType resultDescriptorType; | 56 InterfaceType resultDescriptorType; |
49 InterfaceType listOfResultDescriptorType; | 57 InterfaceType listOfResultDescriptorType; |
50 ClassElement enginePluginClass; | 58 ClassElement enginePluginClass; |
51 CompilationUnitElement taskUnitElement; | 59 CompilationUnitElement taskUnitElement; |
52 InterfaceType extensionPointIdType; | 60 InterfaceType extensionPointIdType; |
53 final String rootDir; | 61 final String rootDir; |
54 | 62 |
55 Driver() | 63 Driver(String pkgPath) : rootDir = new Directory(pkgPath).absolute.path; |
56 : rootDir = | |
57 findRoot(Platform.script.toFilePath(windows: Platform.isWindows)); | |
58 | 64 |
59 /** | 65 /** |
60 * Get an [io.File] object corresponding to the file in which the generated | 66 * Get an [io.File] object corresponding to the file in which the generated |
61 * graph should be output. | 67 * graph should be output. |
62 */ | 68 */ |
63 io.File get file => new io.File( | 69 io.File get file => new io.File( |
64 path.join(rootDir, 'tool', 'task_dependency_graph', 'tasks.dot')); | 70 path.join(rootDir, 'tool', 'task_dependency_graph', 'tasks.dot')); |
65 | 71 |
66 /** | 72 /** |
67 * Determine if the output [file] contains the expected contents. | |
68 */ | |
69 bool checkFile() { | |
70 String expectedContents = generateFileContents(); | |
71 String actualContents = file.readAsStringSync(); | |
72 // Normalize Windows line endings to Unix line endings so that the | |
73 // comparison doesn't fail on Windows. | |
74 actualContents = actualContents.replaceAll('\r\n', '\n'); | |
75 return expectedContents == actualContents; | |
76 } | |
77 | |
78 /** | |
79 * Starting at [node], find all calls to registerExtension() which refer to | 73 * Starting at [node], find all calls to registerExtension() which refer to |
80 * the given [extensionIdVariable], and execute [callback] for the associated | 74 * the given [extensionIdVariable], and execute [callback] for the associated |
81 * result descriptors. | 75 * result descriptors. |
82 */ | 76 */ |
83 void findExtensions(AstNode node, TopLevelVariableElement extensionIdVariable, | 77 void findExtensions(AstNode node, TopLevelVariableElement extensionIdVariable, |
84 void callback(descriptorName)) { | 78 void callback(descriptorName)) { |
85 Set<PropertyAccessorElement> resultDescriptors = | 79 Set<PropertyAccessorElement> resultDescriptors = |
86 new Set<PropertyAccessorElement>(); | 80 new Set<PropertyAccessorElement>(); |
87 node.accept(new ExtensionFinder( | 81 node.accept(new ExtensionFinder( |
88 resultDescriptorType, extensionIdVariable, resultDescriptors.add)); | 82 resultDescriptorType, extensionIdVariable, resultDescriptors.add)); |
(...skipping 27 matching lines...) Expand all Loading... |
116 AstNode node, void callback(String descriptorName)) { | 110 AstNode node, void callback(String descriptorName)) { |
117 Set<PropertyAccessorElement> resultDescriptors = | 111 Set<PropertyAccessorElement> resultDescriptors = |
118 new Set<PropertyAccessorElement>(); | 112 new Set<PropertyAccessorElement>(); |
119 node.accept(new GetterFinder(resultDescriptorType, resultDescriptors.add)); | 113 node.accept(new GetterFinder(resultDescriptorType, resultDescriptors.add)); |
120 for (PropertyAccessorElement resultDescriptor in resultDescriptors) { | 114 for (PropertyAccessorElement resultDescriptor in resultDescriptors) { |
121 callback(resultDescriptor.name); | 115 callback(resultDescriptor.name); |
122 } | 116 } |
123 } | 117 } |
124 | 118 |
125 /** | 119 /** |
126 * Generate the task dependency graph and write it to the output [file]. | |
127 */ | |
128 void generateFile() { | |
129 String fileContents = generateFileContents(); | |
130 file.writeAsStringSync(fileContents); | |
131 } | |
132 | |
133 /** | |
134 * Generate the task dependency graph and return it as a [String]. | 120 * Generate the task dependency graph and return it as a [String]. |
135 */ | 121 */ |
136 String generateFileContents() { | 122 String generateFileContents() { |
137 List<String> lines = <String>[]; | 123 List<String> lines = <String>[]; |
138 resourceProvider = PhysicalResourceProvider.INSTANCE; | 124 resourceProvider = PhysicalResourceProvider.INSTANCE; |
139 DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; | 125 DartSdk sdk = DirectoryBasedDartSdk.defaultSdk; |
140 context = AnalysisEngine.instance.createAnalysisContext(); | 126 context = AnalysisEngine.instance.createAnalysisContext(); |
141 String packageRootPath; | 127 String packageRootPath; |
142 if (Platform.packageRoot.isNotEmpty) { | 128 if (Platform.packageRoot.isNotEmpty) { |
143 packageRootPath = Platform.packageRoot; | 129 packageRootPath = Platform.packageRoot; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 in taskUnitElement.topLevelVariables) { | 247 in taskUnitElement.topLevelVariables) { |
262 if (variable.name == extensionPointId) { | 248 if (variable.name == extensionPointId) { |
263 return variable; | 249 return variable; |
264 } | 250 } |
265 } | 251 } |
266 } | 252 } |
267 } | 253 } |
268 throw new Exception( | 254 throw new Exception( |
269 'Could not find extension ID corresponding to $resultListGetterName'); | 255 'Could not find extension ID corresponding to $resultListGetterName'); |
270 } | 256 } |
271 | |
272 /** | |
273 * Find the root directory of the analyzer package by proceeding | |
274 * upward to the 'tool' dir, and then going up one more directory. | |
275 */ | |
276 static String findRoot(String pathname) { | |
277 while (path.basename(pathname) != 'tool') { | |
278 String parent = path.dirname(pathname); | |
279 if (parent.length >= pathname.length) { | |
280 throw new Exception("Can't find root directory"); | |
281 } | |
282 pathname = parent; | |
283 } | |
284 return path.dirname(pathname); | |
285 } | |
286 } | 257 } |
287 | 258 |
288 /** | 259 /** |
289 * Visitor that finds calls that register extension points. Specifically, we | 260 * Visitor that finds calls that register extension points. Specifically, we |
290 * look for calls of the form `method(extensionIdVariable, resultDescriptor)`, | 261 * look for calls of the form `method(extensionIdVariable, resultDescriptor)`, |
291 * where `resultDescriptor` has type [resultDescriptorType], and we pass the | 262 * where `resultDescriptor` has type [resultDescriptorType], and we pass the |
292 * corresponding result descriptor names to [callback]. | 263 * corresponding result descriptor names to [callback]. |
293 */ | 264 */ |
294 class ExtensionFinder extends GeneralizingAstVisitor { | 265 class ExtensionFinder extends GeneralizingAstVisitor { |
295 final InterfaceType resultDescriptorType; | 266 final InterfaceType resultDescriptorType; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 @override | 309 @override |
339 visitIdentifier(Identifier node) { | 310 visitIdentifier(Identifier node) { |
340 Element element = node.staticElement; | 311 Element element = node.staticElement; |
341 if (element is PropertyAccessorElement && | 312 if (element is PropertyAccessorElement && |
342 element.isGetter && | 313 element.isGetter && |
343 element.returnType.isSubtypeOf(type)) { | 314 element.returnType.isSubtypeOf(type)) { |
344 callback(element); | 315 callback(element); |
345 } | 316 } |
346 } | 317 } |
347 } | 318 } |
OLD | NEW |