mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:37:53 +00:00
Remove IncrementalResolvedAstGenerator.
It is not used anymore, and there is a compilation errors accidentally introduced. So, I guess it is easier to remove it than to fix it. R=ahe@google.com, paulberry@google.com, sigmund@google.com BUG= Review-Url: https://codereview.chromium.org/2892203003 .
This commit is contained in:
parent
54dcc29835
commit
658ff7ba99
|
@ -1,98 +0,0 @@
|
|||
// 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/dart/ast/ast.dart';
|
||||
import 'package:front_end/src/base/processed_options.dart';
|
||||
import 'package:front_end/src/incremental_resolved_ast_generator_impl.dart';
|
||||
|
||||
import 'compiler_options.dart';
|
||||
|
||||
/// Represents the difference between "old" and "new" states of a program.
|
||||
///
|
||||
/// Not intended to be implemented or extended by clients.
|
||||
class DeltaLibraries {
|
||||
/// The new state of the program, as a two-layer map.
|
||||
///
|
||||
/// The outer map key is the library URI. The inner map key is the
|
||||
/// compilation unit (part) URI. The map values are the resolved compilation
|
||||
/// units.
|
||||
///
|
||||
/// Libraries whose resolved AST is known to be unchanged since the last
|
||||
/// [DeltaLibraries] are not included.
|
||||
final Map<Uri, Map<Uri, CompilationUnit>> newState;
|
||||
|
||||
DeltaLibraries(this.newState);
|
||||
|
||||
/// TODO(paulberry): add information about libraries that were removed.
|
||||
}
|
||||
|
||||
/// Interface for generating an initial resolved representation of a program and
|
||||
/// keeping it up to date as incremental changes are made.
|
||||
///
|
||||
/// This class maintains an internal "previous program state"; each
|
||||
/// time [computeDelta] is called, it updates the previous program state and
|
||||
/// produces a representation of what has changed. When there are few changes,
|
||||
/// a call to [computeDelta] should be much faster than compiling the whole
|
||||
/// program from scratch.
|
||||
///
|
||||
/// This class also maintains a set of "valid sources", which is a (possibly
|
||||
/// empty) subset of the sources constituting the previous program state. Files
|
||||
/// in this set are assumed to be unchanged since the last call to
|
||||
/// [computeDelta].
|
||||
///
|
||||
/// Behavior is undefined if the client does not obey the following concurrency
|
||||
/// restrictions:
|
||||
/// - no two invocations of [computeDelta] may be outstanding at any given time.
|
||||
/// - neither [invalidate] nor [invalidateAll] may be called while an invocation
|
||||
/// of [computeDelta] is outstanding.
|
||||
///
|
||||
/// Not intended to be implemented or extended by clients.
|
||||
abstract class IncrementalResolvedAstGenerator {
|
||||
/// Creates an [IncrementalResolvedAstGenerator] which is prepared to generate
|
||||
/// resolved ASTs for the program whose main library is in the given
|
||||
/// [source].
|
||||
///
|
||||
/// No file system access is performed by this constructor; the initial
|
||||
/// "previous program state" is an empty program containing no code, and the
|
||||
/// initial set of valid sources is empty. To obtain a resolved AST
|
||||
/// representation of the program, call [computeDelta].
|
||||
factory IncrementalResolvedAstGenerator(
|
||||
Uri source, CompilerOptions options) =>
|
||||
new IncrementalResolvedAstGeneratorImpl(
|
||||
source, new ProcessedOptions(options));
|
||||
|
||||
/// Generates a resolved AST representation of the changes to the program,
|
||||
/// assuming that all valid sources are unchanged since the last call to
|
||||
/// [computeDelta].
|
||||
///
|
||||
/// Source files in the set of valid sources are guaranteed not to be re-read
|
||||
/// from disk; they are assumed to be unchanged regardless of the state of the
|
||||
/// filesystem.
|
||||
///
|
||||
/// If the future completes successfully, the previous file state is updated
|
||||
/// and the set of valid sources is set to the set of all sources in the
|
||||
/// program.
|
||||
///
|
||||
/// If the future completes with an error (due to errors in the compiled
|
||||
/// source code), the caller may consider the previous file state and the set
|
||||
/// of valid sources to be unchanged; this means that once the user fixes the
|
||||
/// errors, it is safe to call [computeDelta] again.
|
||||
Future<DeltaLibraries> computeDelta();
|
||||
|
||||
/// Remove any source file(s) associated with the given file path from the set
|
||||
/// of valid sources. This guarantees that those files will be re-read on the
|
||||
/// next call to [computeDelta]).
|
||||
void invalidate(String path);
|
||||
|
||||
/// Remove all source files from the set of valid sources. This guarantees
|
||||
/// that all files will be re-read on the next call to [computeDelta].
|
||||
///
|
||||
/// Note that this does not erase the previous program state; the next time
|
||||
/// [computeDelta] is called, if parts of the program are discovered to be
|
||||
/// unchanged, parts of the previous program state will still be re-used to
|
||||
/// speed up compilation.
|
||||
void invalidateAll();
|
||||
}
|
|
@ -7,7 +7,6 @@ import 'dart:io';
|
|||
|
||||
import 'package:front_end/file_system.dart';
|
||||
import 'package:front_end/incremental_kernel_generator.dart';
|
||||
import 'package:front_end/incremental_resolved_ast_generator.dart';
|
||||
import 'package:front_end/src/base/api_signature.dart';
|
||||
import 'package:front_end/src/base/performace_logger.dart';
|
||||
import 'package:front_end/src/base/processed_options.dart';
|
||||
|
|
|
@ -1,303 +0,0 @@
|
|||
// 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/dart/ast/ast.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/context.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/util/absolute_path.dart';
|
||||
import 'package:front_end/incremental_resolved_ast_generator.dart';
|
||||
import 'package:front_end/src/base/file_repository.dart';
|
||||
import 'package:front_end/src/base/performace_logger.dart';
|
||||
import 'package:front_end/src/base/processed_options.dart';
|
||||
import 'package:front_end/src/base/resolve_relative_uri.dart';
|
||||
import 'package:front_end/src/base/source.dart';
|
||||
import 'package:front_end/src/dependency_grapher_impl.dart';
|
||||
import 'package:front_end/src/incremental/byte_store.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 _fileRepository = new FileRepository();
|
||||
_ResourceProviderProxy _resourceProvider;
|
||||
driver.AnalysisDriver _driver;
|
||||
bool _isInitialized = false;
|
||||
final ProcessedOptions _options;
|
||||
final Uri _source;
|
||||
bool _schedulerStarted = false;
|
||||
final _fileState = <Uri, String>{};
|
||||
|
||||
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, fileReader: _fileReader);
|
||||
// TODO(paulberry): collect no-longer-referenced files from _fileState and
|
||||
// _fileRepository.
|
||||
var libraries = <Uri, Map<Uri, CompilationUnit>>{};
|
||||
if (!_schedulerStarted) {
|
||||
_scheduler.start();
|
||||
_schedulerStarted = true;
|
||||
}
|
||||
for (var libraryCycle in graph.topologicallySortedCycles) {
|
||||
for (var libraryUri in libraryCycle.libraries.keys) {
|
||||
var libraryNode = libraryCycle.libraries[libraryUri];
|
||||
for (var partUri in libraryNode.parts) {
|
||||
// TODO(paulberry): resolve the part URI.
|
||||
_fileReader(partUri, partUri);
|
||||
}
|
||||
}
|
||||
for (var libraryUri in libraryCycle.libraries.keys) {
|
||||
var libraryNode = libraryCycle.libraries[libraryUri];
|
||||
var result =
|
||||
await _driver.getResult(_fileRepository.pathForUri(libraryUri));
|
||||
// TODO(paulberry): handle errors.
|
||||
var units = {libraryUri: result.unit};
|
||||
for (var partUri in libraryNode.parts) {
|
||||
// Really we ought to have a driver API that lets us request a
|
||||
// specific part of a given library. Otherwise we will run into
|
||||
// problems if a part is included in multiple libraries.
|
||||
// TODO(paulberry): address this.
|
||||
var partResult =
|
||||
await _driver.getResult(_fileRepository.pathForUri(partUri));
|
||||
// TODO(paulberry): handle errors.
|
||||
units[partUri] = partResult.unit;
|
||||
}
|
||||
libraries[libraryUri] = units;
|
||||
}
|
||||
}
|
||||
_driver.addFile(_fileRepository.pathForUri(_source));
|
||||
// TODO(paulberry): stop the scheduler
|
||||
return new DeltaLibraries(libraries);
|
||||
}
|
||||
|
||||
Future<Null> init() async {
|
||||
// TODO(paulberry): can we just use null?
|
||||
var performanceLog = new PerformanceLog(new _NullStringSink());
|
||||
_scheduler = new driver.AnalysisDriverScheduler(performanceLog);
|
||||
_resourceProvider = new _ResourceProviderProxy(_fileRepository);
|
||||
// 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 sdkBundle = await _options.getSdkSummary();
|
||||
var dartSdk = new _DartSdkProxy(sdkBundle, sdkContext, _fileRepository);
|
||||
sdkContext.sourceFactory =
|
||||
new SourceFactory([new DartUriResolver(dartSdk)]);
|
||||
|
||||
var sourceFactory = new _SourceFactoryProxy(dartSdk, _fileRepository);
|
||||
var analysisOptions = new AnalysisOptionsImpl();
|
||||
_driver = new driver.AnalysisDriver(
|
||||
_scheduler,
|
||||
performanceLog,
|
||||
_resourceProvider,
|
||||
byteStore,
|
||||
fileContentOverlay,
|
||||
null,
|
||||
sourceFactory,
|
||||
analysisOptions,
|
||||
sdkBundle: sdkBundle);
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void invalidate(String path) {
|
||||
throw new UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void invalidateAll() {
|
||||
_fileState.clear();
|
||||
_fileRepository.clearContents();
|
||||
// TODO(paulberry): verify that this has an effect (requires a multi-file
|
||||
// test).
|
||||
if (_isInitialized) {
|
||||
_driver.knownFiles.forEach(_driver.changeFile);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _fileReader(Uri originalUri, Uri resolvedUri) async {
|
||||
String contents = _fileState[resolvedUri] ??=
|
||||
await _options.fileSystem.entityForUri(resolvedUri).readAsString();
|
||||
_fileRepository.store(originalUri, contents);
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
class _DartSdkProxy implements DartSdk {
|
||||
final PackageBundle summary;
|
||||
|
||||
final AnalysisContext context;
|
||||
|
||||
final FileRepository _fileRepository;
|
||||
|
||||
_DartSdkProxy(this.summary, this.context, this._fileRepository);
|
||||
|
||||
@override
|
||||
PackageBundle getLinkedBundle() => summary;
|
||||
|
||||
@override
|
||||
Source mapDartUri(String uriString) {
|
||||
var uri = Uri.parse(uriString);
|
||||
return new _SourceProxy(
|
||||
uri, _fileRepository.pathForUri(uri, allocate: true));
|
||||
}
|
||||
|
||||
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() {
|
||||
return _resourceProvider._fileRepository.contentsForPath(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 FileRepository _fileRepository;
|
||||
|
||||
_ResourceProviderProxy(this._fileRepository);
|
||||
|
||||
@override
|
||||
AbsolutePathContext get absolutePathContext => throw new UnimplementedError();
|
||||
|
||||
@override
|
||||
Context get pathContext => throw new UnimplementedError();
|
||||
|
||||
@override
|
||||
File getFile(String path) {
|
||||
return new _FileProxy(
|
||||
new _SourceProxy(_fileRepository.uriForPath(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 FileRepository _fileRepository;
|
||||
|
||||
@override
|
||||
AnalysisContext context;
|
||||
|
||||
_SourceFactoryProxy(this.dartSdk, this._fileRepository);
|
||||
|
||||
@override
|
||||
SourceFactory clone() => new _SourceFactoryProxy(dartSdk, _fileRepository);
|
||||
|
||||
@override
|
||||
Source forUri(String absoluteUri) {
|
||||
Uri uri = Uri.parse(absoluteUri);
|
||||
return forUri2(uri);
|
||||
}
|
||||
|
||||
@override
|
||||
Source forUri2(Uri absoluteUri) {
|
||||
return new _SourceProxy(
|
||||
absoluteUri, _fileRepository.pathForUri(absoluteUri, allocate: true));
|
||||
}
|
||||
|
||||
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.
|
||||
String absoluteUri =
|
||||
resolveRelativeUri(containingSource?.uri, Uri.parse(containedUri))
|
||||
.toString();
|
||||
return forUri(absoluteUri);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
// 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/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
import 'package:analyzer/src/dart/sdk/sdk.dart';
|
||||
import 'package:front_end/compiler_options.dart';
|
||||
import 'package:front_end/incremental_resolved_ast_generator.dart';
|
||||
import 'package:front_end/memory_file_system.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(IncrementalResolvedAstGeneratorTest);
|
||||
});
|
||||
}
|
||||
|
||||
final _sdkSummary = _readSdkSummary();
|
||||
|
||||
List<int> _readSdkSummary() {
|
||||
var resourceProvider = PhysicalResourceProvider.INSTANCE;
|
||||
var sdk = new FolderBasedDartSdk(resourceProvider,
|
||||
FolderBasedDartSdk.defaultSdkDirectory(resourceProvider))
|
||||
..useSummary = true;
|
||||
var path = resourceProvider.pathContext
|
||||
.join(sdk.directory.path, 'lib', '_internal', 'strong.sum');
|
||||
return resourceProvider.getFile(path).readAsBytesSync();
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class IncrementalResolvedAstGeneratorTest {
|
||||
static final sdkSummaryUri = Uri.parse('special:sdk_summary');
|
||||
|
||||
/// Virtual filesystem for testing.
|
||||
final fileSystem = new MemoryFileSystem(Uri.parse('file:///'));
|
||||
|
||||
/// The object under test.
|
||||
IncrementalResolvedAstGenerator incrementalResolvedAstGenerator;
|
||||
|
||||
Future<Map<Uri, Map<Uri, CompilationUnit>>> getInitialProgram(
|
||||
Uri startingUri) async {
|
||||
fileSystem.entityForUri(sdkSummaryUri).writeAsBytesSync(_sdkSummary);
|
||||
incrementalResolvedAstGenerator = new IncrementalResolvedAstGenerator(
|
||||
startingUri,
|
||||
new CompilerOptions()
|
||||
..fileSystem = fileSystem
|
||||
..chaseDependencies = true
|
||||
..sdkSummary = sdkSummaryUri
|
||||
..packagesFileUri = new Uri());
|
||||
return (await incrementalResolvedAstGenerator.computeDelta()).newState;
|
||||
}
|
||||
|
||||
test_incrementalUpdate_referenceToCore() async {
|
||||
writeFiles({'/foo.dart': 'main() { print(1); }'});
|
||||
var fooUri = Uri.parse('file:///foo.dart');
|
||||
var initialProgram = await getInitialProgram(fooUri);
|
||||
expect(initialProgram.keys, unorderedEquals([fooUri]));
|
||||
|
||||
void _checkMain(CompilationUnit unit, int expectedArgument) {
|
||||
var mainStatements = _getFunctionStatements(_getFunction(unit, 'main'));
|
||||
expect(mainStatements, hasLength(1));
|
||||
_checkPrintLiteralInt(mainStatements[0], expectedArgument);
|
||||
}
|
||||
|
||||
_checkMain(initialProgram[fooUri][fooUri], 1);
|
||||
writeFiles({'/foo.dart': 'main() { print(2); }'});
|
||||
// Verify that the file isn't actually reread until invalidate is called.
|
||||
var deltaProgram1 = await incrementalResolvedAstGenerator.computeDelta();
|
||||
// TODO(paulberry): since there is no delta, computeDelta should return an
|
||||
// empty map.
|
||||
// expect(deltaProgram1.newState, isEmpty);
|
||||
expect(deltaProgram1.newState.keys, unorderedEquals([fooUri]));
|
||||
_checkMain(deltaProgram1.newState[fooUri][fooUri], 1);
|
||||
incrementalResolvedAstGenerator.invalidateAll();
|
||||
var deltaProgram2 = await incrementalResolvedAstGenerator.computeDelta();
|
||||
expect(deltaProgram2.newState.keys, unorderedEquals([fooUri]));
|
||||
_checkMain(deltaProgram2.newState[fooUri][fooUri], 2);
|
||||
}
|
||||
|
||||
test_invalidateAllBeforeInitialProgram() async {
|
||||
incrementalResolvedAstGenerator = new IncrementalResolvedAstGenerator(
|
||||
Uri.parse('file:///foo.dart'),
|
||||
new CompilerOptions()
|
||||
..fileSystem = fileSystem
|
||||
..chaseDependencies = true
|
||||
..packagesFileUri = new Uri());
|
||||
incrementalResolvedAstGenerator.invalidateAll();
|
||||
}
|
||||
|
||||
test_part() async {
|
||||
writeFiles({
|
||||
'/foo.dart': 'library foo; part "bar.dart"; main() { print(1); f(); }',
|
||||
'/bar.dart': 'part of foo; f() { print(2); }'
|
||||
});
|
||||
var fooUri = Uri.parse('file:///foo.dart');
|
||||
var barUri = Uri.parse('file:///bar.dart');
|
||||
var initialProgram = await getInitialProgram(fooUri);
|
||||
expect(initialProgram.keys, unorderedEquals([fooUri]));
|
||||
expect(initialProgram[fooUri].keys, unorderedEquals([fooUri, barUri]));
|
||||
var mainStatements = _getFunctionStatements(
|
||||
_getFunction(initialProgram[fooUri][fooUri], 'main'));
|
||||
var fDeclaration = _getFunction(initialProgram[fooUri][barUri], 'f');
|
||||
var fStatements = _getFunctionStatements(fDeclaration);
|
||||
expect(mainStatements, hasLength(2));
|
||||
_checkPrintLiteralInt(mainStatements[0], 1);
|
||||
_checkFunctionCall(mainStatements[1],
|
||||
resolutionMap.elementDeclaredByFunctionDeclaration(fDeclaration));
|
||||
expect(fStatements, hasLength(1));
|
||||
_checkPrintLiteralInt(fStatements[0], 2);
|
||||
// TODO(paulberry): now test incremental updates
|
||||
}
|
||||
|
||||
/// Write the given file contents to the virtual filesystem.
|
||||
void writeFiles(Map<String, String> contents) {
|
||||
contents.forEach((path, text) {
|
||||
fileSystem
|
||||
.entityForUri(Uri.parse('file://$path'))
|
||||
.writeAsStringSync(text);
|
||||
});
|
||||
}
|
||||
|
||||
void _checkFunctionCall(Statement statement, Element expectedTarget) {
|
||||
expect(statement, new isInstanceOf<ExpressionStatement>());
|
||||
var expressionStatement = statement as ExpressionStatement;
|
||||
expect(
|
||||
expressionStatement.expression, new isInstanceOf<MethodInvocation>());
|
||||
var methodInvocation = expressionStatement.expression as MethodInvocation;
|
||||
expect(
|
||||
resolutionMap.staticElementForIdentifier(methodInvocation.methodName),
|
||||
expectedTarget);
|
||||
}
|
||||
|
||||
void _checkPrintLiteralInt(Statement statement, int expectedArgument) {
|
||||
expect(statement, new isInstanceOf<ExpressionStatement>());
|
||||
var expressionStatement = statement as ExpressionStatement;
|
||||
expect(
|
||||
expressionStatement.expression, new isInstanceOf<MethodInvocation>());
|
||||
var methodInvocation = expressionStatement.expression as MethodInvocation;
|
||||
expect(methodInvocation.methodName.name, 'print');
|
||||
var printElement =
|
||||
resolutionMap.staticElementForIdentifier(methodInvocation.methodName);
|
||||
expect(printElement, isNotNull);
|
||||
expect(printElement.library.source.uri, Uri.parse('dart:core'));
|
||||
expect(methodInvocation.argumentList.arguments, hasLength(1));
|
||||
expect(methodInvocation.argumentList.arguments[0],
|
||||
new isInstanceOf<IntegerLiteral>());
|
||||
var integerLiteral =
|
||||
methodInvocation.argumentList.arguments[0] as IntegerLiteral;
|
||||
expect(integerLiteral.value, expectedArgument);
|
||||
}
|
||||
|
||||
FunctionDeclaration _getFunction(CompilationUnit unit, String name) {
|
||||
for (var declaration in unit.declarations) {
|
||||
if (declaration is FunctionDeclaration && declaration.name.name == name) {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
throw fail('No function declaration found with name "$name"');
|
||||
}
|
||||
|
||||
NodeList<Statement> _getFunctionStatements(FunctionDeclaration function) {
|
||||
var body = function.functionExpression.body;
|
||||
expect(body, new isInstanceOf<BlockFunctionBody>());
|
||||
return (body as BlockFunctionBody).block.statements;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue