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