Backport AnalysisSession.getResolvedLibrary()/ByElement().

Change-Id: I83c1dbe9d758be12212fcd892bb57ae69407d8be
Reviewed-on: https://dart-review.googlesource.com/c/85147
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-11-27 22:53:24 +00:00 committed by commit-bot@chromium.org
parent db89c2d1ac
commit 232aa553fb
8 changed files with 573 additions and 207 deletions

View file

@ -91,6 +91,21 @@ abstract class AnalysisSession {
*/
Future<ResolveResult> getResolvedAst(String path);
/// Return a future that will complete with information about the results of
/// resolving all of the files in the library with the given absolute,
/// normalized [path].
///
/// Throw [ArgumentError] if the given [path] is not the defining compilation
/// unit for a library (that is, is a part of a library).
Future<ResolvedLibraryResult> getResolvedLibrary(String path);
/// Return a future that will complete with information about the results of
/// resolving all of the files in the library with the library [element].
///
/// Throw [ArgumentError] if the [element] was not produced by this session.
Future<ResolvedLibraryResult> getResolvedLibraryByElement(
LibraryElement element);
/**
* Return a future that will complete with the source kind of the file with
* the given absolute, normalized [path]. If the path does not represent a

View file

@ -8,6 +8,7 @@ import 'dart:typed_data';
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/analysis/results.dart' as results;
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart'
@ -24,6 +25,7 @@ import 'package:analyzer/src/dart/analysis/index.dart';
import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
import 'package:analyzer/src/dart/analysis/library_context.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/search.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/analysis/status.dart';
@ -186,6 +188,13 @@ class AnalysisDriver implements AnalysisDriverGeneric {
*/
final _requestedFiles = <String, List<Completer<AnalysisResult>>>{};
/**
* The mapping from the files for which analysis was requested using
* [getResolvedLibrary] to the [Completer]s to report the result.
*/
final _requestedLibraries =
<String, List<Completer<ResolvedLibraryResult>>>{};
/**
* The task that discovers available files. If this field is not `null`,
* and the task is not completed, it should be performed and completed
@ -468,6 +477,9 @@ class AnalysisDriver implements AnalysisDriverGeneric {
if (_requestedFiles.isNotEmpty) {
return AnalysisDriverPriority.interactive;
}
if (_requestedLibraries.isNotEmpty) {
return AnalysisDriverPriority.interactive;
}
if (_discoverAvailableFilesTask != null &&
!_discoverAvailableFilesTask.isCompleted) {
return AnalysisDriverPriority.interactive;
@ -725,6 +737,83 @@ class AnalysisDriver implements AnalysisDriverGeneric {
return unitResult.element.library;
}
/**
* Return a [Future] that completes with a [ResolvedLibraryResult] for the
* Dart library file with the given [path]. If the file is not a Dart file
* or cannot be analyzed, the [Future] completes with `null`.
*
* Throw [ArgumentError] if the given [path] is not the defining compilation
* unit for a library (that is, is a part of a library).
*
* The [path] must be absolute and normalized.
*
* The [path] can be any file - explicitly or implicitly analyzed, or neither.
*
* Invocation of this method causes the analysis state to transition to
* "analyzing" (if it is not in that state already), the driver will produce
* the resolution result for it, which is consistent with the current file
* state (including new states of the files previously reported using
* [changeFile]), prior to the next time the analysis state transitions
* to "idle".
*/
Future<ResolvedLibraryResult> getResolvedLibrary(String path) {
_throwIfNotAbsolutePath(path);
if (!_fsState.hasUri(path)) {
return new Future.value();
}
FileState file = _fsState.getFileForPath(path);
if (file.isExternalLibrary) {
return Future.value(
ResolvedLibraryResultImpl.external(currentSession, file.uri),
);
}
if (file.isPart) {
throw ArgumentError('Is a part: $path');
}
// Schedule analysis.
var completer = new Completer<ResolvedLibraryResult>();
_requestedLibraries
.putIfAbsent(path, () => <Completer<ResolvedLibraryResult>>[])
.add(completer);
_scheduler.notify(this);
return completer.future;
}
/**
* Return a [Future] that completes with a [ResolvedLibraryResult] for the
* Dart library file with the given [uri].
*
* Throw [ArgumentError] if the given [uri] is not the defining compilation
* unit for a library (that is, is a part of a library).
*
* Invocation of this method causes the analysis state to transition to
* "analyzing" (if it is not in that state already), the driver will produce
* the resolution result for it, which is consistent with the current file
* state (including new states of the files previously reported using
* [changeFile]), prior to the next time the analysis state transitions
* to "idle".
*/
Future<ResolvedLibraryResult> getResolvedLibraryByUri(Uri uri) {
FileState file = _fsState.getFileForUri(uri);
if (file.isExternalLibrary) {
return Future.value(
ResolvedLibraryResultImpl.external(currentSession, file.uri),
);
}
if (file.isPart) {
throw ArgumentError('Is a part: $uri');
}
// The file is a local file, we can get the result.
return getResolvedLibrary(file.path);
}
ApiSignature getResolvedUnitKeyByPath(String path) {
_throwIfNotAbsolutePath(path);
ApiSignature signature = getUnitKeyByPath(path);
@ -959,6 +1048,22 @@ class AnalysisDriver implements AnalysisDriverGeneric {
return;
}
// Analyze a requested library.
if (_requestedLibraries.isNotEmpty) {
String path = _requestedLibraries.keys.first;
try {
var result = _computeResolvedLibrary(path);
_requestedLibraries.remove(path).forEach((completer) {
completer.complete(result);
});
} catch (exception, stackTrace) {
_requestedLibraries.remove(path).forEach((completer) {
completer.completeError(exception, stackTrace);
});
}
return;
}
// Process an index request.
if (_indexRequestedFiles.isNotEmpty) {
String path = _indexRequestedFiles.keys.first;
@ -1256,7 +1361,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
if (!_fsState.getFileForUri(Uri.parse('dart:async')).exists) {
return _newMissingDartLibraryResult(file, 'dart:async');
}
libraryContext = await _createLibraryContext(library);
libraryContext = _createLibraryContext(library);
LibraryAnalyzer analyzer = new LibraryAnalyzer(
analysisOptions,
@ -1267,7 +1372,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
libraryContext.resynthesizer,
library,
_resourceProvider);
Map<FileState, UnitAnalysisResult> results = await analyzer.analyze();
Map<FileState, UnitAnalysisResult> results = analyzer.analyze();
List<int> bytes;
CompilationUnit resolvedUnit;
@ -1319,6 +1424,62 @@ class AnalysisDriver implements AnalysisDriverGeneric {
return analysisResult._index;
}
/**
* Return the newly computed resolution result of the library with the
* given [path].
*/
ResolvedLibraryResultImpl _computeResolvedLibrary(String path) {
FileState library = _fsState.getFileForPath(path);
return _logger.run('Compute resolved library $path', () {
_testView.numOfAnalyzedLibraries++;
var libraryContext = _createLibraryContext(library);
LibraryAnalyzer analyzer = new LibraryAnalyzer(
analysisOptions,
declaredVariables,
sourceFactory,
libraryContext.isLibraryUri,
libraryContext.analysisContext,
libraryContext.resynthesizer,
library,
_resourceProvider);
Map<FileState, UnitAnalysisResult> unitResults = analyzer.analyze();
var resolvedUnits = <ResolvedUnitResult>[];
for (var unitFile in unitResults.keys) {
if (unitFile.path != null) {
var unitResult = unitResults[unitFile];
resolvedUnits.add(
new AnalysisResult(
this,
_sourceFactory,
unitFile.path,
unitFile.uri,
unitFile.exists,
unitFile.content,
unitFile.lineInfo,
unitFile.isPart,
null,
unitResult.unit,
unitResult.errors,
null,
),
);
}
}
return new ResolvedLibraryResultImpl(
currentSession,
library.path,
library.uri,
resolvedUnits.first.libraryElement,
libraryContext.analysisContext.typeProvider,
resolvedUnits,
);
});
}
Future<UnitElementResult> _computeUnitElement(String path,
{bool asIsIfPartWithoutLibrary: false}) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
@ -1335,7 +1496,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
}
}
LibraryContext libraryContext = await _createLibraryContext(library);
LibraryContext libraryContext = _createLibraryContext(library);
try {
CompilationUnitElement element =
libraryContext.computeUnitElement(library.source, file.source);
@ -1389,9 +1550,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
/**
* Return the context in which the [library] should be analyzed.
*/
Future<LibraryContext> _createLibraryContext(FileState library) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
LibraryContext _createLibraryContext(FileState library) {
_testView.numOfCreatedLibraryContexts++;
return new LibraryContext.forSingleLibrary(
library,
@ -1955,7 +2114,7 @@ class AnalysisDriverTestView {
FileState library = driver.fsState.getFileForPath(libraryPath);
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
LibraryContext libraryContext = await driver._createLibraryContext(library);
LibraryContext libraryContext = driver._createLibraryContext(library);
try {
return libraryContext.store;
} finally {
@ -1975,7 +2134,7 @@ class AnalysisDriverTestView {
* Every result is independent, and is not guaranteed to be consistent with
* any previously returned result, even inside of the same library.
*/
class AnalysisResult extends FileResult implements results.ResolveResult {
class AnalysisResult extends FileResult implements results.ResolvedUnitResult {
static final _UNCHANGED = new AnalysisResult(
null, null, null, null, null, null, null, null, null, null, null, null);

View file

@ -213,11 +213,26 @@ class FileState {
*/
List<FileState> get importedFiles => _importedFiles;
/**
* Return `true` if the file is a stub created for a library in the provided
* external summary store.
*/
bool get isExternalLibrary {
return _fsState.externalSummaries != null &&
_fsState.externalSummaries.linkedMap.containsKey(uriStr);
}
/**
* Return `true` if the file does not have a `library` directive, and has a
* `part of` directive, so is probably a part.
*/
bool get isPart => _unlinked.libraryNameOffset == 0 && _unlinked.isPartOf;
bool get isPart {
if (_fsState.externalSummaries != null &&
_fsState.externalSummaries.unlinkedMap.containsKey(uriStr)) {
return !_fsState.externalSummaries.linkedMap.containsKey(uriStr);
}
return _unlinked.libraryNameOffset == 0 && _unlinked.isPartOf;
}
/**
* Return `true` if the file is the "unresolved" file, which does not have

View file

@ -2,8 +2,6 @@
// 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/analysis/declared_variables.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@ -94,10 +92,8 @@ class LibraryAnalyzer {
/**
* Compute analysis results for all units of the library.
*/
Future<Map<FileState, UnitAnalysisResult>> analyze() async {
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
return PerformanceStatistics.analysis.makeCurrentWhileAsync(() async {
Map<FileState, UnitAnalysisResult> analyze() {
return PerformanceStatistics.analysis.makeCurrentWhile(() {
return analyzeSync();
});
}

View file

@ -143,9 +143,6 @@ class ResolvedLibraryResultImpl extends AnalysisResultImpl
@override
final LibraryElement element;
@override
final ResultState state = ResultState.VALID;
@override
final TypeProvider typeProvider;
@ -156,8 +153,23 @@ class ResolvedLibraryResultImpl extends AnalysisResultImpl
this.element, this.typeProvider, this.units)
: super(session, path, uri);
ResolvedLibraryResultImpl.external(AnalysisSession session, Uri uri)
: this(session, null, uri, null, null, null);
@override
ResultState get state {
if (path == null) {
return ResultState.NOT_A_FILE;
}
return ResultState.VALID;
}
@override
ElementDeclarationResult getElementDeclaration(Element element) {
if (state != ResultState.VALID) {
throw StateError('The result is not valid: $state');
}
var elementPath = element.source.fullName;
var unitResult = units.firstWhere(
(r) => r.path == elementPath,

View file

@ -129,6 +129,20 @@ class AnalysisSessionImpl implements AnalysisSession {
return _driver.getResult(path);
}
@override
Future<ResolvedLibraryResult> getResolvedLibrary(String path) {
_checkConsistency();
return _driver.getResolvedLibrary(path);
}
@override
Future<ResolvedLibraryResult> getResolvedLibraryByElement(
LibraryElement element) {
_checkConsistency();
_checkElementOfThisSession(element);
return _driver.getResolvedLibraryByUri(element.source.uri);
}
@override
Future<SourceKind> getSourceKind(String path) {
_checkConsistency();
@ -163,4 +177,13 @@ class AnalysisSessionImpl implements AnalysisSession {
throw new InconsistentAnalysisException();
}
}
void _checkElementOfThisSession(Element element) {
// TODO(scheglov) Requires 2.2 implementation
// if (element.session != this) {
// throw new ArgumentError(
// '(${element.runtimeType}) $element was not produced by '
// 'this session.');
// }
}
}

View file

@ -4,6 +4,7 @@
import 'dart:async';
import 'package:analyzer/dart/analysis/results.dart' as results;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
@ -1572,6 +1573,89 @@ class Test {}
expect(coreLibrary.getType('Object'), isNotNull);
}
test_getResolvedLibrary_external() async {
var a1 = _p('/aaa/lib/a1.dart');
var a2 = _p('/aaa/lib/a2.dart');
var a1UriStr = 'package:aaa/a1.dart';
var a2UriStr = 'package:aaa/a2.dart';
provider.newFile(a1, "part 'a2.dart'; class A {}");
provider.newFile(a2, "part of 'a1.dart';");
// Build the store with the library.
var store = await createAnalysisDriver().test.getSummaryStore(a1);
expect(store.unlinkedMap.keys, contains(a1UriStr));
expect(store.unlinkedMap.keys, contains(a2UriStr));
expect(store.linkedMap.keys, contains(a1UriStr));
var driver = createAnalysisDriver(externalSummaries: store);
var libraryElement = await driver.getLibraryByUri(a1UriStr);
var classA = libraryElement.library.getType('A');
var resolvedLibrary = await driver.getResolvedLibrary(a1);
expect(resolvedLibrary, isNotNull);
expect(resolvedLibrary.state, results.ResultState.NOT_A_FILE);
expect(() {
resolvedLibrary.getElementDeclaration(classA);
}, throwsStateError);
// It is an error to ask for a library when we know that it is a part.
expect(() async {
await driver.getResolvedLibrary(a2);
}, throwsArgumentError);
}
test_getResolvedLibraryByUri_external() async {
var a1 = _p('/aaa/lib/a1.dart');
var a2 = _p('/aaa/lib/a2.dart');
var a1UriStr = 'package:aaa/a1.dart';
var a2UriStr = 'package:aaa/a2.dart';
var a1Uri = Uri.parse(a1UriStr);
var a2Uri = Uri.parse(a2UriStr);
provider.newFile(a1, "part 'a2.dart'; class A {}");
provider.newFile(a2, "part of 'a1.dart';");
// Build the store with the library.
var store = await createAnalysisDriver().test.getSummaryStore(a1);
expect(store.unlinkedMap.keys, contains(a1UriStr));
expect(store.unlinkedMap.keys, contains(a2UriStr));
expect(store.linkedMap.keys, contains(a1UriStr));
var driver = createAnalysisDriver(externalSummaries: store);
var libraryElement = await driver.getLibraryByUri(a1UriStr);
var classA = libraryElement.library.getType('A');
{
var resolvedLibrary = await driver.getResolvedLibraryByUri(a1Uri);
expect(resolvedLibrary, isNotNull);
expect(resolvedLibrary.state, results.ResultState.NOT_A_FILE);
expect(() {
resolvedLibrary.getElementDeclaration(classA);
}, throwsStateError);
}
// We can also get the result from the session.
{
var session = driver.currentSession;
var resolvedLibrary =
await session.getResolvedLibraryByElement(libraryElement);
expect(resolvedLibrary, isNotNull);
expect(resolvedLibrary.state, results.ResultState.NOT_A_FILE);
expect(() {
resolvedLibrary.getElementDeclaration(classA);
}, throwsStateError);
}
// It is an error to ask for a library when we know that it is a part.
expect(() async {
await driver.getResolvedLibraryByUri(a2Uri);
}, throwsArgumentError);
}
test_getResult() async {
String content = 'int f() => 42;';
addTestFile(content, priority: true);

View file

@ -2,23 +2,18 @@
// 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/analysis/session.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisOptions, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../context/mock_sdk.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnalysisSessionImplTest);
@ -26,214 +21,281 @@ main() {
}
@reflectiveTest
class AnalysisSessionImplTest {
MockAnalysisDriver driver;
class AnalysisSessionImplTest with ResourceProviderMixin {
AnalysisContextCollection contextCollection;
AnalysisContext context;
AnalysisSessionImpl session;
String testContextPath;
String aaaContextPath;
String bbbContextPath;
String testPath;
void setUp() {
driver = new MockAnalysisDriver();
session = new AnalysisSessionImpl(driver);
driver.currentSession = session;
MockSdk(resourceProvider: resourceProvider);
testContextPath = newFolder('/home/test').path;
aaaContextPath = newFolder('/home/aaa').path;
bbbContextPath = newFolder('/home/bbb').path;
newFile('/home/test/.packages', content: r'''
test:lib/
''');
contextCollection = AnalysisContextCollectionImpl(
includedPaths: [testContextPath, aaaContextPath, bbbContextPath],
resourceProvider: resourceProvider,
sdkPath: convertPath(sdkRoot),
);
context = contextCollection.contextFor(testContextPath);
session = context.currentSession;
testPath = convertPath('/home/test/lib/test.dart');
}
test_getErrors() async {
ErrorsResult result = new ErrorsResult(null, null, null, null, null, null);
driver.errorsResult = result;
expect(await session.getErrors('path'), result);
newFile(testPath, content: 'class C {');
var errorsResult = await session.getErrors(testPath);
expect(errorsResult.session, session);
expect(errorsResult.path, testPath);
expect(errorsResult.errors, isNotEmpty);
}
test_getLibraryByUri() async {
String uri = 'uri';
newFile(testPath, content: r'''
class A {}
class B {}
''');
var source = new _SourceMock(Uri.parse(uri));
var unit = new CompilationUnitElementImpl()
..librarySource = source
..source = source;
var library = new LibraryElementImpl(null, null, null, null)
..definingCompilationUnit = unit;
driver.libraryMap[uri] = library;
expect(await session.getLibraryByUri(uri), library);
var library = await session.getLibraryByUri('package:test/test.dart');
expect(library.getType('A'), isNotNull);
expect(library.getType('B'), isNotNull);
expect(library.getType('C'), isNull);
}
test_getParsedAst() async {
ParseResult result =
new ParseResult(null, null, null, null, null, null, null, null);
driver.parseResult = result;
expect(await session.getParsedAst('path'), result);
test_getParsedAstSync() async {
newFile(testPath, content: r'''
class A {}
class B {}
''');
var unitResult = session.getParsedAstSync(testPath);
expect(unitResult.session, session);
expect(unitResult.path, testPath);
expect(unitResult.uri, Uri.parse('package:test/test.dart'));
expect(unitResult.unit.declarations, hasLength(2));
}
test_getResolvedAst() async {
AnalysisResult result = new AnalysisResult(driver, null, null, null, null,
null, null, null, null, null, null, null);
driver.result = result;
expect(await session.getResolvedAst('path'), result);
newFile(testPath, content: r'''
class A {}
class B {}
''');
var unitResult = await session.getResolvedAst(testPath);
expect(unitResult.session, session);
expect(unitResult.path, testPath);
expect(unitResult.uri, Uri.parse('package:test/test.dart'));
expect(unitResult.unit.declarations, hasLength(2));
expect(unitResult.typeProvider, isNotNull);
expect(unitResult.libraryElement, isNotNull);
}
test_getResolvedLibrary() async {
var a = convertPath('/home/test/lib/a.dart');
var b = convertPath('/home/test/lib/b.dart');
var aContent = r'''
part 'b.dart';
class A /*a*/ {}
''';
newFile(a, content: aContent);
var bContent = r'''
part of 'a.dart';
class B /*b*/ {}
class B2 extends X {}
''';
newFile(b, content: bContent);
var resolvedLibrary = await session.getResolvedLibrary(a);
expect(resolvedLibrary.session, session);
expect(resolvedLibrary.path, a);
expect(resolvedLibrary.uri, Uri.parse('package:test/a.dart'));
var typeProvider = resolvedLibrary.typeProvider;
expect(typeProvider.intType.element.name, 'int');
var libraryElement = resolvedLibrary.element;
expect(libraryElement, isNotNull);
var aClass = libraryElement.getType('A');
expect(aClass, isNotNull);
var bClass = libraryElement.getType('B');
expect(bClass, isNotNull);
var aUnitResult = resolvedLibrary.units[0];
expect(aUnitResult.path, a);
expect(aUnitResult.uri, Uri.parse('package:test/a.dart'));
expect(aUnitResult.content, aContent);
expect(aUnitResult.unit, isNotNull);
expect(aUnitResult.unit.directives, hasLength(1));
expect(aUnitResult.unit.declarations, hasLength(1));
expect(aUnitResult.errors, isEmpty);
var bUnitResult = resolvedLibrary.units[1];
expect(bUnitResult.path, b);
expect(bUnitResult.uri, Uri.parse('package:test/b.dart'));
expect(bUnitResult.content, bContent);
expect(bUnitResult.unit, isNotNull);
expect(bUnitResult.unit.directives, hasLength(1));
expect(bUnitResult.unit.declarations, hasLength(2));
expect(bUnitResult.errors, isNotEmpty);
var aDeclaration = resolvedLibrary.getElementDeclaration(aClass);
ClassDeclaration aNode = aDeclaration.node;
expect(aNode.name.name, 'A');
expect(aNode.offset, 16);
expect(aNode.length, 16);
expect(aNode.name.staticElement.name, 'A');
var bDeclaration = resolvedLibrary.getElementDeclaration(bClass);
ClassDeclaration bNode = bDeclaration.node;
expect(bNode.name.name, 'B');
expect(bNode.offset, 19);
expect(bNode.length, 16);
expect(bNode.name.staticElement.name, 'B');
}
test_getResolvedLibrary_getElementDeclaration_notThisLibrary() async {
newFile(testPath, content: '');
var resolvedLibrary = await session.getResolvedLibrary(testPath);
expect(() {
var intClass = resolvedLibrary.typeProvider.intType.element;
resolvedLibrary.getElementDeclaration(intClass);
}, throwsArgumentError);
}
test_getResolvedLibrary_getElementDeclaration_synthetic() async {
newFile(testPath, content: r'''
int foo = 0;
''');
var resolvedLibrary = await session.getResolvedLibrary(testPath);
var unitElement = resolvedLibrary.element.definingCompilationUnit;
var fooElement = unitElement.topLevelVariables[0];
expect(fooElement.name, 'foo');
// We can get the variable element declaration.
var fooDeclaration = resolvedLibrary.getElementDeclaration(fooElement);
VariableDeclaration fooNode = fooDeclaration.node;
expect(fooNode.name.name, 'foo');
expect(fooNode.offset, 4);
expect(fooNode.length, 7);
expect(fooNode.name.staticElement.name, 'foo');
// Synthetic elements don't have nodes.
expect(resolvedLibrary.getElementDeclaration(fooElement.getter), isNull);
expect(resolvedLibrary.getElementDeclaration(fooElement.setter), isNull);
}
test_getResolvedLibrary_invalidPartUri() async {
newFile(testPath, content: r'''
part 'a.dart';
part ':[invalid uri].dart';
part 'c.dart';
''');
var resolvedLibrary = await session.getResolvedLibrary(testPath);
expect(resolvedLibrary.units, hasLength(3));
expect(
resolvedLibrary.units[0].path,
convertPath('/home/test/lib/test.dart'),
);
expect(
resolvedLibrary.units[1].path,
convertPath('/home/test/lib/a.dart'),
);
expect(
resolvedLibrary.units[2].path,
convertPath('/home/test/lib/c.dart'),
);
}
test_getResolvedLibrary_notLibrary() async {
newFile(testPath, content: 'part of "a.dart";');
expect(() {
session.getResolvedLibrary(testPath);
}, throwsArgumentError);
}
test_getResolvedLibraryByElement() async {
newFile(testPath, content: '');
var element = await session.getLibraryByUri('package:test/test.dart');
var resolvedLibrary = await session.getResolvedLibraryByElement(element);
expect(resolvedLibrary.session, session);
expect(resolvedLibrary.path, testPath);
expect(resolvedLibrary.uri, Uri.parse('package:test/test.dart'));
expect(resolvedLibrary.units, hasLength(1));
expect(resolvedLibrary.units[0].unit.declaredElement, isNotNull);
}
test_getSourceKind() async {
SourceKind kind = SourceKind.LIBRARY;
driver.sourceKind = kind;
expect(await session.getSourceKind('path'), kind);
newFile(testPath, content: 'class C {}');
var kind = await session.getSourceKind(testPath);
expect(kind, SourceKind.LIBRARY);
}
test_getTopLevelDeclarations() async {
List<TopLevelDeclarationInSource> declarations = [];
driver.topLevelDeclarations = declarations;
expect(await session.getTopLevelDeclarations('path'), declarations);
test_getSourceKind_part() async {
newFile(testPath, content: 'part of "a.dart";');
var kind = await session.getSourceKind(testPath);
expect(kind, SourceKind.PART);
}
test_getUnitElement() async {
UnitElementResult result =
new UnitElementResult(null, null, null, null, null);
driver.unitElementResult = result;
expect(await session.getUnitElement('path'), result);
newFile(testPath, content: r'''
class A {}
class B {}
''');
var unitResult = await session.getUnitElement(testPath);
expect(unitResult.session, session);
expect(unitResult.path, testPath);
expect(unitResult.uri, Uri.parse('package:test/test.dart'));
expect(unitResult.element.types, hasLength(2));
var signature = await session.getUnitElementSignature(testPath);
expect(unitResult.signature, signature);
}
test_getUnitElementSignature() async {
String signature = 'xyzzy';
driver.unitElementSignature = signature;
expect(await session.getUnitElementSignature('path'), signature);
}
test_resourceProvider() {
ResourceProvider resourceProvider = new MemoryResourceProvider();
driver.resourceProvider = resourceProvider;
test_resourceProvider() async {
expect(session.resourceProvider, resourceProvider);
}
test_sourceFactory() {
SourceFactory sourceFactory = new SourceFactory([]);
driver.sourceFactory = sourceFactory;
expect(session.sourceFactory, sourceFactory);
}
test_typeProvider() async {
_initializeSDK();
expect(await session.typeProvider, isNotNull);
var typeProvider = await session.typeProvider;
expect(typeProvider.intType.element.name, 'int');
}
test_typeSystem() async {
_initializeSDK();
expect(await session.typeSystem, isNotNull);
}
void _initializeSDK() {
CompilationUnitElementImpl newUnit(String name) {
CompilationUnitElementImpl unit = new CompilationUnitElementImpl();
unit.accessors = [];
unit.enums = [];
unit.functions = [];
unit.typeAliases = [];
return unit;
}
ClassElementImpl newClass(String name) {
TypeParameterElementImpl param = new TypeParameterElementImpl('E', 0);
param.type = new TypeParameterTypeImpl(param);
ClassElementImpl element = new ClassElementImpl(name, 0);
element.typeParameters = [param];
return element;
}
{
CompilationUnitElementImpl coreUnit = newUnit('dart.core');
coreUnit.types = <ClassElement>[newClass('Iterable')];
LibraryElementImpl core = new LibraryElementImpl(null, null, null, null);
core.definingCompilationUnit = coreUnit;
driver.libraryMap['dart:core'] = core;
}
{
CompilationUnitElementImpl asyncUnit = newUnit('dart.async');
asyncUnit.types = <ClassElement>[
newClass('Future'),
newClass('FutureOr'),
newClass('Stream')
];
LibraryElementImpl async = new LibraryElementImpl(null, null, null, null);
async.definingCompilationUnit = asyncUnit;
driver.libraryMap['dart:async'] = async;
}
}
}
class MockAnalysisDriver implements AnalysisDriver {
@override
AnalysisSession currentSession;
ErrorsResult errorsResult;
Map<String, LibraryElement> libraryMap = <String, LibraryElement>{};
ParseResult parseResult;
ResourceProvider resourceProvider;
AnalysisResult result;
SourceFactory sourceFactory;
SourceKind sourceKind;
List<TopLevelDeclarationInSource> topLevelDeclarations;
UnitElementResult unitElementResult;
String unitElementSignature;
AnalysisOptions get analysisOptions => new AnalysisOptionsImpl();
@override
Future<ErrorsResult> getErrors(String path) async {
return errorsResult;
}
@override
Future<LibraryElement> getLibraryByUri(String uri) async {
return libraryMap[uri];
}
@override
Future<AnalysisResult> getResult(String path,
{bool sendCachedToStream: false}) async {
return result;
}
@override
Future<SourceKind> getSourceKind(String path) async {
return sourceKind;
}
@override
Future<List<TopLevelDeclarationInSource>> getTopLevelNameDeclarations(
String name) async {
return topLevelDeclarations;
}
@override
Future<UnitElementResult> getUnitElement(String path) async {
return unitElementResult;
}
@override
Future<String> getUnitElementSignature(String path) async {
return unitElementSignature;
}
@override
dynamic noSuchMethod(Invocation invocation) {
fail('Unexpected invocation of ${invocation.memberName}');
}
@override
Future<ParseResult> parseFile(String path) async {
return parseResult;
}
@override
ParseResult parseFileSync(String path) {
return parseResult;
}
}
class _SourceMock implements Source {
@override
final Uri uri;
_SourceMock(this.uri);
@override
noSuchMethod(Invocation invocation) {
throw new StateError('Unexpected invocation of ${invocation.memberName}');
var typeSystem = await session.typeSystem;
var typeProvider = typeSystem.typeProvider;
expect(
typeSystem.isSubtypeOf(typeProvider.intType, typeProvider.numType),
isTrue,
);
}
}