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