OLD | NEW |
| (Empty) |
1 // Copyright (c) 2017, 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 import 'dart:async'; | |
6 | |
7 import 'package:analyzer/dart/ast/ast.dart'; | |
8 import 'package:analyzer/file_system/file_system.dart'; | |
9 import 'package:analyzer/src/context/context.dart'; | |
10 import 'package:analyzer/src/dart/analysis/driver.dart' as driver; | |
11 import 'package:analyzer/src/dart/analysis/file_state.dart'; | |
12 import 'package:analyzer/src/generated/engine.dart'; | |
13 import 'package:analyzer/src/generated/sdk.dart'; | |
14 import 'package:analyzer/src/generated/source.dart'; | |
15 import 'package:analyzer/src/summary/idl.dart'; | |
16 import 'package:analyzer/src/util/absolute_path.dart'; | |
17 import 'package:front_end/incremental_resolved_ast_generator.dart'; | |
18 import 'package:front_end/src/base/file_repository.dart'; | |
19 import 'package:front_end/src/base/performace_logger.dart'; | |
20 import 'package:front_end/src/base/processed_options.dart'; | |
21 import 'package:front_end/src/base/resolve_relative_uri.dart'; | |
22 import 'package:front_end/src/base/source.dart'; | |
23 import 'package:front_end/src/dependency_grapher_impl.dart'; | |
24 import 'package:front_end/src/incremental/byte_store.dart'; | |
25 import 'package:path/src/context.dart'; | |
26 | |
27 dynamic unimplemented() { | |
28 // TODO(paulberry): get rid of this. | |
29 throw new UnimplementedError(); | |
30 } | |
31 | |
32 /// Implementation of [IncrementalKernelGenerator]. | |
33 /// | |
34 /// Theory of operation: this class is a thin wrapper around | |
35 /// [driver.AnalysisDriver]. When the client requests a new delta, we forward | |
36 /// the request to the analysis driver. When the client calls an invalidate | |
37 /// method, we ensure that the proper files will be re-read next time a delta is | |
38 /// requested. | |
39 /// | |
40 /// Note that the analysis driver expects to be able to read file contents | |
41 /// synchronously based on filesystem path rather than asynchronously based on | |
42 /// URI, so the file contents are first read into memory using the asynchronous | |
43 /// FileSystem API, and then these are fed into the analysis driver using a | |
44 /// proxy implementation of [ResourceProvider]. TODO(paulberry): make this (and | |
45 /// other proxies in this file) unnecessary. | |
46 class IncrementalResolvedAstGeneratorImpl | |
47 implements IncrementalResolvedAstGenerator { | |
48 driver.AnalysisDriverScheduler _scheduler; | |
49 final _fileRepository = new FileRepository(); | |
50 _ResourceProviderProxy _resourceProvider; | |
51 driver.AnalysisDriver _driver; | |
52 bool _isInitialized = false; | |
53 final ProcessedOptions _options; | |
54 final Uri _source; | |
55 bool _schedulerStarted = false; | |
56 final _fileState = <Uri, String>{}; | |
57 | |
58 IncrementalResolvedAstGeneratorImpl(this._source, this._options); | |
59 | |
60 @override | |
61 Future<DeltaLibraries> computeDelta() async { | |
62 if (!_isInitialized) { | |
63 await init(); | |
64 } | |
65 // The analysis driver doesn't currently support an asynchronous file API, | |
66 // so we have to find all the files first to read their contents. | |
67 // TODO(paulberry): this is an unnecessary source of duplicate work and | |
68 // should be eliminated ASAP. | |
69 var graph = | |
70 await graphForProgram([_source], _options, fileReader: _fileReader); | |
71 // TODO(paulberry): collect no-longer-referenced files from _fileState and | |
72 // _fileRepository. | |
73 var libraries = <Uri, Map<Uri, CompilationUnit>>{}; | |
74 if (!_schedulerStarted) { | |
75 _scheduler.start(); | |
76 _schedulerStarted = true; | |
77 } | |
78 for (var libraryCycle in graph.topologicallySortedCycles) { | |
79 for (var libraryUri in libraryCycle.libraries.keys) { | |
80 var libraryNode = libraryCycle.libraries[libraryUri]; | |
81 for (var partUri in libraryNode.parts) { | |
82 // TODO(paulberry): resolve the part URI. | |
83 _fileReader(partUri, partUri); | |
84 } | |
85 } | |
86 for (var libraryUri in libraryCycle.libraries.keys) { | |
87 var libraryNode = libraryCycle.libraries[libraryUri]; | |
88 var result = | |
89 await _driver.getResult(_fileRepository.pathForUri(libraryUri)); | |
90 // TODO(paulberry): handle errors. | |
91 var units = {libraryUri: result.unit}; | |
92 for (var partUri in libraryNode.parts) { | |
93 // Really we ought to have a driver API that lets us request a | |
94 // specific part of a given library. Otherwise we will run into | |
95 // problems if a part is included in multiple libraries. | |
96 // TODO(paulberry): address this. | |
97 var partResult = | |
98 await _driver.getResult(_fileRepository.pathForUri(partUri)); | |
99 // TODO(paulberry): handle errors. | |
100 units[partUri] = partResult.unit; | |
101 } | |
102 libraries[libraryUri] = units; | |
103 } | |
104 } | |
105 _driver.addFile(_fileRepository.pathForUri(_source)); | |
106 // TODO(paulberry): stop the scheduler | |
107 return new DeltaLibraries(libraries); | |
108 } | |
109 | |
110 Future<Null> init() async { | |
111 // TODO(paulberry): can we just use null? | |
112 var performanceLog = new PerformanceLog(new _NullStringSink()); | |
113 _scheduler = new driver.AnalysisDriverScheduler(performanceLog); | |
114 _resourceProvider = new _ResourceProviderProxy(_fileRepository); | |
115 // TODO(paulberry): MemoryByteStore leaks memory (it never discards data). | |
116 // Do something better here. | |
117 var byteStore = new MemoryByteStore(); | |
118 // TODO(paulberry): can we just use null? | |
119 var fileContentOverlay = new FileContentOverlay(); | |
120 var sdkContext = new AnalysisContextImpl(); | |
121 var sdkBundle = await _options.getSdkSummary(); | |
122 var dartSdk = new _DartSdkProxy(sdkBundle, sdkContext, _fileRepository); | |
123 sdkContext.sourceFactory = | |
124 new SourceFactory([new DartUriResolver(dartSdk)]); | |
125 | |
126 var sourceFactory = new _SourceFactoryProxy(dartSdk, _fileRepository); | |
127 var analysisOptions = new AnalysisOptionsImpl(); | |
128 _driver = new driver.AnalysisDriver( | |
129 _scheduler, | |
130 performanceLog, | |
131 _resourceProvider, | |
132 byteStore, | |
133 fileContentOverlay, | |
134 null, | |
135 sourceFactory, | |
136 analysisOptions, | |
137 sdkBundle: sdkBundle); | |
138 _isInitialized = true; | |
139 } | |
140 | |
141 @override | |
142 void invalidate(String path) { | |
143 throw new UnimplementedError(); | |
144 } | |
145 | |
146 @override | |
147 void invalidateAll() { | |
148 _fileState.clear(); | |
149 _fileRepository.clearContents(); | |
150 // TODO(paulberry): verify that this has an effect (requires a multi-file | |
151 // test). | |
152 if (_isInitialized) { | |
153 _driver.knownFiles.forEach(_driver.changeFile); | |
154 } | |
155 } | |
156 | |
157 Future<String> _fileReader(Uri originalUri, Uri resolvedUri) async { | |
158 String contents = _fileState[resolvedUri] ??= | |
159 await _options.fileSystem.entityForUri(resolvedUri).readAsString(); | |
160 _fileRepository.store(originalUri, contents); | |
161 return contents; | |
162 } | |
163 } | |
164 | |
165 class _DartSdkProxy implements DartSdk { | |
166 final PackageBundle summary; | |
167 | |
168 final AnalysisContext context; | |
169 | |
170 final FileRepository _fileRepository; | |
171 | |
172 _DartSdkProxy(this.summary, this.context, this._fileRepository); | |
173 | |
174 @override | |
175 PackageBundle getLinkedBundle() => summary; | |
176 | |
177 @override | |
178 Source mapDartUri(String uriString) { | |
179 var uri = Uri.parse(uriString); | |
180 return new _SourceProxy( | |
181 uri, _fileRepository.pathForUri(uri, allocate: true)); | |
182 } | |
183 | |
184 noSuchMethod(Invocation invocation) => unimplemented(); | |
185 } | |
186 | |
187 class _FileProxy implements File { | |
188 final _SourceProxy _source; | |
189 | |
190 final _ResourceProviderProxy _resourceProvider; | |
191 | |
192 _FileProxy(this._source, this._resourceProvider); | |
193 | |
194 @override | |
195 String get path => _source.fullName; | |
196 | |
197 @override | |
198 String get shortName => path; | |
199 | |
200 @override | |
201 Source createSource([Uri uri]) { | |
202 assert(uri == null); | |
203 return _source; | |
204 } | |
205 | |
206 noSuchMethod(Invocation invocation) => unimplemented(); | |
207 | |
208 @override | |
209 String readAsStringSync() { | |
210 return _resourceProvider._fileRepository.contentsForPath(path); | |
211 } | |
212 } | |
213 | |
214 /// A string sink that ignores everything written to it. | |
215 class _NullStringSink implements StringSink { | |
216 void write(Object obj) {} | |
217 void writeAll(Iterable objects, [String separator = ""]) {} | |
218 void writeCharCode(int charCode) {} | |
219 void writeln([Object obj = ""]) {} | |
220 } | |
221 | |
222 class _ResourceProviderProxy implements ResourceProvider { | |
223 final FileRepository _fileRepository; | |
224 | |
225 _ResourceProviderProxy(this._fileRepository); | |
226 | |
227 @override | |
228 AbsolutePathContext get absolutePathContext => throw new UnimplementedError(); | |
229 | |
230 @override | |
231 Context get pathContext => throw new UnimplementedError(); | |
232 | |
233 @override | |
234 File getFile(String path) { | |
235 return new _FileProxy( | |
236 new _SourceProxy(_fileRepository.uriForPath(path), path), this); | |
237 } | |
238 | |
239 @override | |
240 Folder getFolder(String path) => throw new UnimplementedError(); | |
241 | |
242 @override | |
243 Future<List<int>> getModificationTimes(List<Source> sources) => | |
244 throw new UnimplementedError(); | |
245 | |
246 @override | |
247 Resource getResource(String path) => throw new UnimplementedError(); | |
248 | |
249 @override | |
250 Folder getStateLocation(String pluginId) => throw new UnimplementedError(); | |
251 } | |
252 | |
253 class _SourceFactoryProxy implements SourceFactory { | |
254 @override | |
255 final DartSdk dartSdk; | |
256 | |
257 final FileRepository _fileRepository; | |
258 | |
259 @override | |
260 AnalysisContext context; | |
261 | |
262 _SourceFactoryProxy(this.dartSdk, this._fileRepository); | |
263 | |
264 @override | |
265 SourceFactory clone() => new _SourceFactoryProxy(dartSdk, _fileRepository); | |
266 | |
267 @override | |
268 Source forUri(String absoluteUri) { | |
269 Uri uri = Uri.parse(absoluteUri); | |
270 return forUri2(uri); | |
271 } | |
272 | |
273 @override | |
274 Source forUri2(Uri absoluteUri) { | |
275 return new _SourceProxy( | |
276 absoluteUri, _fileRepository.pathForUri(absoluteUri, allocate: true)); | |
277 } | |
278 | |
279 noSuchMethod(Invocation invocation) => unimplemented(); | |
280 | |
281 Source resolveUri(Source containingSource, String containedUri) { | |
282 // TODO(paulberry): re-use code from dependency_grapher_impl, and support | |
283 // SDK URI resolution logic. | |
284 String absoluteUri = | |
285 resolveRelativeUri(containingSource?.uri, Uri.parse(containedUri)) | |
286 .toString(); | |
287 return forUri(absoluteUri); | |
288 } | |
289 | |
290 @override | |
291 Uri restoreUri(Source source) => source.uri; | |
292 } | |
293 | |
294 class _SourceProxy extends BasicSource { | |
295 @override | |
296 final String fullName; | |
297 | |
298 _SourceProxy(Uri uri, this.fullName) : super(uri); | |
299 | |
300 int get modificationStamp => 0; | |
301 | |
302 noSuchMethod(Invocation invocation) => unimplemented(); | |
303 } | |
OLD | NEW |