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>
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index 1760f2a..b945ed6 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -91,6 +91,21 @@
*/
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
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 000fcae..6f2d3ec 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -8,6 +8,7 @@
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/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';
@@ -187,6 +189,13 @@
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
* before any name searching task.
@@ -468,6 +477,9 @@
if (_requestedFiles.isNotEmpty) {
return AnalysisDriverPriority.interactive;
}
+ if (_requestedLibraries.isNotEmpty) {
+ return AnalysisDriverPriority.interactive;
+ }
if (_discoverAvailableFilesTask != null &&
!_discoverAvailableFilesTask.isCompleted) {
return AnalysisDriverPriority.interactive;
@@ -725,6 +737,83 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- LibraryContext libraryContext = await _createLibraryContext(library);
+ LibraryContext libraryContext = _createLibraryContext(library);
try {
CompilationUnitElement element =
libraryContext.computeUnitElement(library.source, file.source);
@@ -1389,9 +1550,7 @@
/**
* 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 @@
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 @@
* 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);
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index f9da8aa..e627abb 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -214,10 +214,25 @@
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
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 6c421b8..ed45474 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -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 @@
/**
* 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();
});
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index 2f1eb6c..2b9ac07 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -144,9 +144,6 @@
final LibraryElement element;
@override
- final ResultState state = ResultState.VALID;
-
- @override
final TypeProvider typeProvider;
@override
@@ -156,8 +153,23 @@
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,
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 982f3bb..b44d556 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -130,6 +130,20 @@
}
@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();
return _driver.getSourceKind(path);
@@ -163,4 +177,13 @@
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.');
+// }
+ }
}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 1afe213..0345738 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -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 @@
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);
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index 0c00794..a5b9b87 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -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 @@
}
@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,
+ );
}
}