| Index: pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
|
| diff --git a/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart b/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..22a91c2b75354a94a360fb9022bef8d0ad850b03
|
| --- /dev/null
|
| +++ b/pkg/front_end/lib/src/incremental_resolved_ast_generator_impl.dart
|
| @@ -0,0 +1,279 @@
|
| +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'dart:async';
|
| +
|
| +import 'package:analyzer/file_system/file_system.dart';
|
| +import 'package:analyzer/src/context/context.dart';
|
| +import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
| +import 'package:analyzer/src/dart/analysis/driver.dart' as driver;
|
| +import 'package:analyzer/src/dart/analysis/file_state.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/sdk.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/summary/idl.dart';
|
| +import 'package:analyzer/src/summary/summary_sdk.dart';
|
| +import 'package:analyzer/src/util/absolute_path.dart';
|
| +import 'package:front_end/incremental_resolved_ast_generator.dart';
|
| +import 'package:front_end/src/base/processed_options.dart';
|
| +import 'package:front_end/src/base/source.dart';
|
| +import 'package:front_end/src/dependency_grapher_impl.dart';
|
| +import 'package:path/src/context.dart';
|
| +
|
| +dynamic unimplemented() {
|
| + // TODO(paulberry): get rid of this.
|
| + throw new UnimplementedError();
|
| +}
|
| +
|
| +/// Implementation of [IncrementalKernelGenerator].
|
| +///
|
| +/// Theory of operation: this class is a thin wrapper around
|
| +/// [driver.AnalysisDriver]. When the client requests a new delta, we forward
|
| +/// the request to the analysis driver. When the client calls an invalidate
|
| +/// method, we ensure that the proper files will be re-read next time a delta is
|
| +/// requested.
|
| +///
|
| +/// Note that the analysis driver expects to be able to read file contents
|
| +/// synchronously based on filesystem path rather than asynchronously based on
|
| +/// URI, so the file contents are first read into memory using the asynchronous
|
| +/// FileSystem API, and then these are fed into the analysis driver using a
|
| +/// proxy implementation of [ResourceProvider]. TODO(paulberry): make this (and
|
| +/// other proxies in this file) unnecessary.
|
| +class IncrementalResolvedAstGeneratorImpl
|
| + implements IncrementalResolvedAstGenerator {
|
| + driver.AnalysisDriverScheduler _scheduler;
|
| + final _pathToUriMap = <String, Uri>{};
|
| + final _uriToPathMap = <Uri, String>{};
|
| + final _fileContents = <String, String>{};
|
| + _ResourceProviderProxy _resourceProvider;
|
| + driver.AnalysisDriver _driver;
|
| + bool _isInitialized = false;
|
| + final ProcessedOptions _options;
|
| + final Uri _source;
|
| +
|
| + IncrementalResolvedAstGeneratorImpl(this._source, this._options);
|
| +
|
| + @override
|
| + Future<DeltaLibraries> computeDelta() async {
|
| + if (!_isInitialized) {
|
| + await init();
|
| + }
|
| + // The analysis driver doesn't currently support an asynchronous file API,
|
| + // so we have to find all the files first to read their contents.
|
| + // TODO(paulberry): this is an unnecessary source of duplicate work and
|
| + // should be eliminated ASAP.
|
| + var graph = await graphForProgram([_source], _options);
|
| + var libraries = <Uri, ResolvedLibrary>{};
|
| + // TODO(paulberry): it should be possible to seed the driver using a URI,
|
| + // not a file path.
|
| + // TODO(paulberry): only start the scheduler the first time.
|
| + _scheduler.start();
|
| + _driver.addFile(_source.path);
|
| + for (var libraryCycle in graph.topologicallySortedCycles) {
|
| + for (var uri in libraryCycle.libraries.keys) {
|
| + var contents =
|
| + await _options.fileSystem.entityForUri(uri).readAsString();
|
| + _storeVirtualFile(uri, uri.path, contents);
|
| + }
|
| + // The driver will request files from dart:, even though it actually uses
|
| + // the data from the summary. TODO(paulberry): fix this.
|
| + _storeVirtualFile(_DartSdkProxy._dartCoreSource.uri, 'core.dart', '');
|
| + for (var uri in libraryCycle.libraries.keys) {
|
| + var result = await _driver.getResult(uri.path);
|
| + // TODO(paulberry): handle errors.
|
| + libraries[uri] = new ResolvedLibrary(result.unit);
|
| + }
|
| + }
|
| + // TODO(paulberry): stop the scheduler
|
| + return new DeltaLibraries(libraries);
|
| + }
|
| +
|
| + Future<Null> init() async {
|
| + // TODO(paulberry): can we just use null?
|
| + var performanceLog = new driver.PerformanceLog(new _NullStringSink());
|
| + _scheduler = new driver.AnalysisDriverScheduler(performanceLog);
|
| + _resourceProvider =
|
| + new _ResourceProviderProxy(_fileContents, _pathToUriMap);
|
| + // TODO(paulberry): MemoryByteStore leaks memory (it never discards data).
|
| + // Do something better here.
|
| + var byteStore = new MemoryByteStore();
|
| + // TODO(paulberry): can we just use null?
|
| + var fileContentOverlay = new FileContentOverlay();
|
| + var sdkContext = new AnalysisContextImpl();
|
| + var dartSdk = new _DartSdkProxy(await _options.getSdkSummary(), sdkContext);
|
| + sdkContext.sourceFactory =
|
| + new SourceFactory([new DartUriResolver(dartSdk)]);
|
| + bool strongMode = true; // TODO(paulberry): support strong mode flag.
|
| + sdkContext.resultProvider = new SdkSummaryResultProvider(
|
| + sdkContext, await _options.getSdkSummary(), strongMode);
|
| +
|
| + var sourceFactory =
|
| + new _SourceFactoryProxy(dartSdk, _pathToUriMap, _uriToPathMap);
|
| + var analysisOptions = new AnalysisOptionsImpl();
|
| + _driver = new driver.AnalysisDriver(
|
| + _scheduler,
|
| + performanceLog,
|
| + _resourceProvider,
|
| + byteStore,
|
| + fileContentOverlay,
|
| + sourceFactory,
|
| + analysisOptions);
|
| + _isInitialized = true;
|
| + }
|
| +
|
| + @override
|
| + void invalidate(String path) {
|
| + throw new UnimplementedError();
|
| + }
|
| +
|
| + @override
|
| + void invalidateAll() {
|
| + throw new UnimplementedError();
|
| + }
|
| +
|
| + void _storeVirtualFile(Uri uri, String path, String contents) {
|
| + _pathToUriMap[path] = uri;
|
| + _uriToPathMap[uri] = path;
|
| + _fileContents[path] = contents;
|
| + }
|
| +}
|
| +
|
| +class _DartSdkProxy implements DartSdk {
|
| + static final _dartCoreSource =
|
| + new _SourceProxy(Uri.parse('dart:core'), 'core.dart');
|
| +
|
| + final PackageBundle summary;
|
| +
|
| + final AnalysisContext context;
|
| +
|
| + _DartSdkProxy(this.summary, this.context);
|
| +
|
| + @override
|
| + PackageBundle getLinkedBundle() => summary;
|
| +
|
| + @override
|
| + Source mapDartUri(String uri) {
|
| + // TODO(paulberry): this seems hacky.
|
| + return new _SourceProxy(Uri.parse(uri), '$uri.dart');
|
| + }
|
| +
|
| + noSuchMethod(Invocation invocation) => unimplemented();
|
| +}
|
| +
|
| +class _FileProxy implements File {
|
| + final _SourceProxy _source;
|
| +
|
| + final _ResourceProviderProxy _resourceProvider;
|
| +
|
| + _FileProxy(this._source, this._resourceProvider);
|
| +
|
| + @override
|
| + String get path => _source.fullName;
|
| +
|
| + @override
|
| + String get shortName => path;
|
| +
|
| + @override
|
| + Source createSource([Uri uri]) {
|
| + assert(uri == null);
|
| + return _source;
|
| + }
|
| +
|
| + noSuchMethod(Invocation invocation) => unimplemented();
|
| +
|
| + @override
|
| + String readAsStringSync() {
|
| + assert(_resourceProvider.fileContents.containsKey(path));
|
| + return _resourceProvider.fileContents[path];
|
| + }
|
| +}
|
| +
|
| +/// A string sink that ignores everything written to it.
|
| +class _NullStringSink implements StringSink {
|
| + void write(Object obj) {}
|
| + void writeAll(Iterable objects, [String separator = ""]) {}
|
| + void writeCharCode(int charCode) {}
|
| + void writeln([Object obj = ""]) {}
|
| +}
|
| +
|
| +class _ResourceProviderProxy implements ResourceProvider {
|
| + final Map<String, String> fileContents;
|
| + final Map<String, Uri> pathToUriMap;
|
| +
|
| + _ResourceProviderProxy(this.fileContents, this.pathToUriMap);
|
| +
|
| + @override
|
| + AbsolutePathContext get absolutePathContext => throw new UnimplementedError();
|
| +
|
| + @override
|
| + Context get pathContext => throw new UnimplementedError();
|
| +
|
| + @override
|
| + File getFile(String path) {
|
| + assert(fileContents.containsKey(path));
|
| + assert(pathToUriMap.containsKey(path));
|
| + return new _FileProxy(new _SourceProxy(pathToUriMap[path], path), this);
|
| + }
|
| +
|
| + @override
|
| + Folder getFolder(String path) => throw new UnimplementedError();
|
| +
|
| + @override
|
| + Future<List<int>> getModificationTimes(List<Source> sources) =>
|
| + throw new UnimplementedError();
|
| +
|
| + @override
|
| + Resource getResource(String path) => throw new UnimplementedError();
|
| +
|
| + @override
|
| + Folder getStateLocation(String pluginId) => throw new UnimplementedError();
|
| +}
|
| +
|
| +class _SourceFactoryProxy implements SourceFactory {
|
| + @override
|
| + final DartSdk dartSdk;
|
| +
|
| + final Map<String, Uri> pathToUriMap;
|
| +
|
| + final Map<Uri, String> uriToPathMap;
|
| +
|
| + @override
|
| + AnalysisContext context;
|
| +
|
| + _SourceFactoryProxy(this.dartSdk, this.pathToUriMap, this.uriToPathMap);
|
| +
|
| + @override
|
| + SourceFactory clone() => this;
|
| +
|
| + @override
|
| + Source forUri(String absoluteUri) {
|
| + if (absoluteUri == 'dart:core') return _DartSdkProxy._dartCoreSource;
|
| + Uri uri = Uri.parse(absoluteUri);
|
| + assert(uriToPathMap.containsKey(uri));
|
| + return new _SourceProxy(uri, uriToPathMap[uri]);
|
| + }
|
| +
|
| + noSuchMethod(Invocation invocation) => unimplemented();
|
| +
|
| + Source resolveUri(Source containingSource, String containedUri) {
|
| + // TODO(paulberry): re-use code from dependency_grapher_impl, and support
|
| + // SDK URI resolution logic.
|
| + var absoluteUri = containingSource.uri.resolve(containedUri);
|
| + return forUri(absoluteUri.toString());
|
| + }
|
| +
|
| + @override
|
| + Uri restoreUri(Source source) => source.uri;
|
| +}
|
| +
|
| +class _SourceProxy extends BasicSource {
|
| + @override
|
| + final String fullName;
|
| +
|
| + _SourceProxy(Uri uri, this.fullName) : super(uri);
|
| +
|
| + int get modificationStamp => 0;
|
| +
|
| + noSuchMethod(Invocation invocation) => unimplemented();
|
| +}
|
|
|