Add all SDK libraries, and context files belonging to the package / potions of it.

R=brianwilkerson@google.com

Change-Id: I7e5d6cc12657c92f16d65e89f4b60eacf16c51b6
Reviewed-on: https://dart-review.googlesource.com/c/91260
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov 2019-01-27 22:33:04 +00:00 committed by commit-bot@chromium.org
parent f92b816268
commit d927333c52
2 changed files with 537 additions and 165 deletions

View file

@ -13,6 +13,7 @@ import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/string_source.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:analyzer/src/summary/format.dart' as idl;
@ -54,12 +55,23 @@ class DeclarationsContext {
/// the root are included into completion, even in 'lib/src' folders.
final AnalysisContext _analysisContext;
/// Map of path prefixes to lists of files from dependencies (both libraries
/// and parts, we don't know at the time when we fill this map) that
/// libraries with files paths starting with these prefixes can access.
/// Packages in the analysis context.
///
/// Packages are sorted so that inner packages are before outer.
final List<_Package> _packages = [];
/// The list of paths of all files inside the context.
final List<String> _contextPathList = [];
/// The list of paths of all SDK libraries.
final List<String> _sdkLibraryPathList = [];
/// Map of path prefixes to lists of paths of files from dependencies
/// (both libraries and parts, we don't know at the time when we fill this
/// map) that libraries with paths starting with these prefixes can access.
///
/// The path prefix keys are sorted so that the longest keys are first.
final Map<String, List<String>> _pathPrefixToDependencyFiles = {};
final Map<String, List<String>> _pathPrefixToDependencyPathList = {};
DeclarationsContext(this._tracker, this._analysisContext);
@ -71,20 +83,49 @@ class DeclarationsContext {
///
/// With `Bazel` sets of accessible libraries are specified explicitly by
/// the client using [setDependencies].
List<int> getLibraries(String path) {
// TODO(scheglov) include context libraries
for (var pathPrefix in _pathPrefixToDependencyFiles.keys) {
Libraries getLibraries(String path) {
var sdkLibraries = <Library>[];
_addLibrariesWithPaths(sdkLibraries, _sdkLibraryPathList);
var dependencyLibraries = <Library>[];
for (var pathPrefix in _pathPrefixToDependencyPathList.keys) {
if (path.startsWith(pathPrefix)) {
var pathList = _pathPrefixToDependencyFiles[pathPrefix];
var idList = pathList
.map((libPath) => _tracker._pathToFile[libPath])
.where((file) => file != null && file.isLibrary)
.map((file) => file.id)
.toList();
return idList;
var pathList = _pathPrefixToDependencyPathList[pathPrefix];
_addLibrariesWithPaths(dependencyLibraries, pathList);
break;
}
}
return <int>[];
_Package package;
for (var candidatePackage in _packages) {
if (candidatePackage.contains(path)) {
package = candidatePackage;
break;
}
}
var contextPathList = <String>[];
if (package != null) {
var containingFolder = package.folderInRootContaining(path);
if (containingFolder != null) {
for (var contextPath in _contextPathList) {
// `lib/` can see only libraries in `lib/`.
// `test/` can see libraries in `lib/` and in `test/`.
if (package.containsInLib(contextPath) ||
containingFolder.contains(contextPath)) {
contextPathList.add(contextPath);
}
}
}
} else {
// Not in a package, include all libraries of the context.
contextPathList = _contextPathList;
}
var contextLibraries = <Library>[];
_addLibrariesWithPaths(contextLibraries, contextPathList);
return Libraries(sdkLibraries, dependencyLibraries, contextLibraries);
}
/// Set dependencies for path prefixes in this context.
@ -106,7 +147,7 @@ class DeclarationsContext {
/// Every path in the list must be absolute and normalized.
void setDependencies(Map<String, List<String>> pathPrefixToPathList) {
var rootFolder = _analysisContext.contextRoot.root;
_pathPrefixToDependencyFiles.removeWhere((pathPrefix, _) {
_pathPrefixToDependencyPathList.removeWhere((pathPrefix, _) {
return rootFolder.isOrContains(pathPrefix);
});
@ -122,10 +163,68 @@ class DeclarationsContext {
var resource = _tracker._resourceProvider.getResource(path);
_scheduleDependencyResource(files, resource);
}
_pathPrefixToDependencyFiles[pathPrefix] = files;
_pathPrefixToDependencyPathList[pathPrefix] = files;
}
}
void _addLibrariesWithPaths(List<Library> libraries, List<String> pathList) {
for (var path in pathList) {
var file = _tracker._pathToFile[path];
if (file != null && file.isLibrary) {
var library = _tracker._idToLibrary[file.id];
if (library != null) {
libraries.add(library);
}
}
}
}
/// Traverse the folders of this context and fill [_packages]; use
/// `pubspec.yaml` files to set `Pub` dependencies.
void _findPackages() {
var pathContext = _tracker._resourceProvider.pathContext;
var pubPathPrefixToPathList = <String, List<String>>{};
void visitFolder(Folder folder) {
var buildFile = folder.getChildAssumingFile('BUILD');
var pubspecFile = folder.getChildAssumingFile('pubspec.yaml');
if (buildFile.exists) {
_packages.add(_Package(folder));
} else if (pubspecFile.exists) {
var dependencies = _parsePubspecDependencies(pubspecFile);
var libPaths = _resolvePackageNamesToLibPaths(dependencies.lib);
var devPaths = _resolvePackageNamesToLibPaths(dependencies.dev);
var packagePath = folder.path;
pubPathPrefixToPathList[packagePath] = <String>[]
..addAll(libPaths)
..addAll(devPaths);
var libPath = pathContext.join(packagePath, 'lib');
pubPathPrefixToPathList[libPath] = libPaths;
_packages.add(_Package(folder));
}
try {
for (var resource in folder.getChildren()) {
if (resource is Folder) {
visitFolder(resource);
}
}
} on FileSystemException {}
}
visitFolder(_analysisContext.contextRoot.root);
setDependencies(pubPathPrefixToPathList);
_packages.sort((a, b) {
var aRoot = a.root.path;
var bRoot = b.root.path;
return bRoot.compareTo(aRoot);
});
}
bool _isLibSrcPath(String path) {
var parts = _tracker._resourceProvider.pathContext.split(path);
for (var i = 0; i < parts.length - 1; ++i) {
@ -167,6 +266,7 @@ class DeclarationsContext {
void _scheduleContextFiles() {
var contextFiles = _analysisContext.contextRoot.analyzedFiles();
for (var path in contextFiles) {
_contextPathList.add(path);
_tracker._addFile(this, path);
}
}
@ -189,39 +289,17 @@ class DeclarationsContext {
}
}
/// Traverse the folders of this context, and use `pubspec.yaml` files
/// to set dependencies for containing folders.
void _setPubspecDependencies() {
var pathContext = _tracker._resourceProvider.pathContext;
var locationToPathList = <String, List<String>>{};
void visitFolder(Folder folder) {
var pubspecFile = folder.getChildAssumingFile('pubspec.yaml');
if (pubspecFile.exists) {
var dependencies = _parsePubspecDependencies(pubspecFile);
var libPaths = _resolvePackageNamesToLibPaths(dependencies.lib);
var devPaths = _resolvePackageNamesToLibPaths(dependencies.dev);
var packagePath = folder.path;
locationToPathList[packagePath] = <String>[]
..addAll(libPaths)
..addAll(devPaths);
var libPath = pathContext.join(packagePath, 'lib');
locationToPathList[libPath] = libPaths;
void _scheduleSdkLibraries() {
// ignore: deprecated_member_use_from_same_package
var sdk = _analysisContext.currentSession.sourceFactory.dartSdk;
for (var uriStr in sdk.uris) {
var uri = Uri.parse(uriStr);
var path = _resolveUri(uri);
if (path != null) {
_sdkLibraryPathList.add(path);
_tracker._addFile(this, path);
}
try {
for (var resource in folder.getChildren()) {
if (resource is Folder) {
visitFolder(resource);
}
}
} on FileSystemException {}
}
visitFolder(_analysisContext.contextRoot.root);
setDependencies(locationToPathList);
}
static _PubspecDependencies _parsePubspecDependencies(File pubspecFile) {
@ -257,6 +335,7 @@ class DeclarationsTracker {
final Map<AnalysisContext, DeclarationsContext> _contexts = {};
final Map<String, _File> _pathToFile = {};
final Map<Uri, _File> _uriToFile = {};
final Map<int, Library> _idToLibrary = {};
final _changesController = _StreamController<LibraryChange>();
@ -286,7 +365,8 @@ class DeclarationsTracker {
_contexts[analysisContext] = declarationsContext;
declarationsContext._scheduleContextFiles();
declarationsContext._setPubspecDependencies();
declarationsContext._scheduleSdkLibraries();
declarationsContext._findPackages();
return declarationsContext;
}
@ -325,6 +405,7 @@ class DeclarationsTracker {
file.uri,
file.exportedDeclarations,
);
_idToLibrary[file.id] = library;
_changesController.add(
LibraryChange._([library], []),
);
@ -385,6 +466,14 @@ class DeclarationsTracker {
}
}
class Libraries {
final List<Library> sdk;
final List<Library> dependencies;
final List<Library> context;
Libraries(this.sdk, this.dependencies, this.context);
}
/// A library with declarations.
class Library {
/// The unique identifier of a library with the given [path].
@ -400,6 +489,11 @@ class Library {
final List<Declaration> declarations;
Library._(this.id, this.path, this.uri, this.declarations);
@override
String toString() {
return '(uri: $uri, path: $path)';
}
}
/// A change to the set of libraries and their declarations.
@ -607,7 +701,7 @@ class _File {
/// Return the [_File] for the given [relative] URI, maybe `null`.
_File _fileForRelativeUri(DeclarationsContext context, Uri relative) {
var absoluteUri = uri.resolveUri(relative);
var absoluteUri = resolveRelativeUri(uri, relative);
return tracker._getFileByUri(context, absoluteUri);
}
@ -810,6 +904,42 @@ class _LibraryWalker extends graph.DependencyWalker<_LibraryNode> {
}
}
/// Information about a package: `Pub` or `Bazel`.
class _Package {
final Folder root;
final Folder lib;
_Package(this.root) : lib = root.getChildAssumingFolder('lib');
/// Return `true` if the [path] is anywhere in the [root] of the package.
///
/// Note, that this method does not check if the are nested packages, that
/// might actually contain the [path].
bool contains(String path) {
return root.contains(path);
}
/// Return `true` if the [path] is in the `lib` folder of this package.
bool containsInLib(String path) {
return lib.contains(path);
}
/// Return the direct child folder of the root, that contains the [path].
///
/// So, we can know if the [path] is in `lib/`, or `test/`, or `bin/`.
Folder folderInRootContaining(String path) {
try {
var children = root.getChildren();
for (var folder in children) {
if (folder is Folder && folder.contains(path)) {
return folder;
}
}
} on FileSystemException {}
return null;
}
}
class _Part {
final Uri uri;

View file

@ -9,6 +9,7 @@ import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/services/available_declarations.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:meta/meta.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -25,9 +26,15 @@ class AbstractContextTest with ResourceProviderMixin {
AnalysisContext testAnalysisContext;
void addTestPackageDependency(String name, String rootPath) {
var packagesFile = getFile('/home/test/.packages');
var packagesContent = packagesFile.readAsStringSync();
void addDotPackagesDependency(String path, String name, String rootPath) {
var packagesFile = getFile(path);
String packagesContent;
try {
packagesContent = packagesFile.readAsStringSync();
} catch (_) {
packagesContent = '';
}
// Ignore if there is already the same package dependency.
if (packagesContent.contains('$name:file://')) {
@ -42,6 +49,10 @@ class AbstractContextTest with ResourceProviderMixin {
createAnalysisContexts();
}
void addTestPackageDependency(String name, String rootPath) {
addDotPackagesDependency('/home/test/.packages', name, rootPath);
}
/// Create all analysis contexts in `/home`.
void createAnalysisContexts() {
analysisContextCollection = AnalysisContextCollectionImpl(
@ -66,8 +77,8 @@ class AbstractContextTest with ResourceProviderMixin {
new MockSdk(resourceProvider: resourceProvider);
newFolder('/home/test');
newFile('/home/test/.packages', content: r'''
test:file:///home/test/lib
newFile('/home/test/.packages', content: '''
test:${toUri('/home/test/lib')}
''');
createAnalysisContexts();
@ -245,133 +256,309 @@ mixin B {}
], uriStr: 'package:test/test.dart');
}
test_getLibraries_pub() async {
newFile('/home/aaa/lib/a.dart', content: r'''
class A {}
''');
newFile('/home/aaa/lib/src/a2.dart', content: r'''
class A2 {}
''');
test_getLibraries_bazel() async {
newFile('/home/aaa/lib/a.dart', content: 'class A {}');
newFile('/home/aaa/lib/src/a2.dart', content: 'class A2 {}');
newFile('/home/bbb/lib/b.dart', content: r'''
class B {}
''');
newFile('/home/bbb/lib/src/b2.dart', content: r'''
class B2 {}
''');
newFile('/home/bbb/lib/b.dart', content: 'class B {}');
newFile('/home/bbb/lib/src/b2.dart', content: 'class B2 {}');
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
newFile('/home/material_button/BUILD', content: '');
newFile(
'/home/material_button/lib/button.dart',
content: 'class MaterialButton {}',
);
newFile(
'/home/material_button/test/button_test.dart',
content: 'class MaterialButtonTest {}',
);
newFile('/home/test/pubspec.yaml', content: r'''
name: test
newFile('/home/material_button/testing/BUILD', content: '');
newFile(
'/home/material_button/testing/lib/material_button_po.dart',
content: 'class MaterialButtonPO {}',
);
dependencies:
aaa: any
dev_dependencies:
bbb: any
''');
newFile('/home/test/lib/test.dart', content: '');
var context = tracker.addContext(testAnalysisContext);
var packagesFilePath = '/home/material_button/.packages';
addDotPackagesDependency(packagesFilePath, 'aaa', '/home/aaa');
addDotPackagesDependency(packagesFilePath, 'bbb', '/home/bbb');
addDotPackagesDependency(
packagesFilePath,
'material_button',
'/home/material_button',
);
addDotPackagesDependency(
packagesFilePath,
'material_button_testing',
'/home/material_button/testing',
);
var analysisContext = analysisContextCollection.contextFor(
convertPath('/home/material_button'),
);
var context = tracker.addContext(analysisContext);
context.setDependencies({
convertPath('/home/material_button'): [convertPath('/home/aaa/lib')],
convertPath('/home/material_button/testing'): [
convertPath('/home/bbb/lib'),
convertPath('/home/material_button/lib'),
],
});
await _doAllTrackerWork();
var aUri = 'package:aaa/a.dart';
var bUri = 'package:bbb/b.dart';
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('A'),
], uriStr: aUri);
], uriStr: 'package:aaa/a.dart');
_assertNoLibrary('package:aaa/src/a2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('B'),
], uriStr: bUri);
], uriStr: 'package:bbb/b.dart');
_assertNoLibrary('package:bbb/src/b2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('MaterialButton'),
], uriStr: 'package:material_button/button.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('MaterialButtonTest'),
], uriStr: toUri('/home/material_button/test/button_test.dart').toString());
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('MaterialButtonPO'),
], uriStr: 'package:material_button_testing/material_button_po.dart');
// package/lib can see only regular dependencies
{
var path = convertPath('/home/test/lib/a.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(idList, isNot(contains(uriToLibrary[bUri].id)));
var path = convertPath('/home/material_button/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
_assertHasLibraries(
libraries.context,
uriList: [
'package:material_button/button.dart',
],
only: true,
);
}
// package/bin can see regular and dev dependencies
{
var path = convertPath('/home/test/bin/b.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(idList, contains(uriToLibrary[bUri].id));
var path = convertPath('/home/material_button/test/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
_assertHasLibraries(
libraries.context,
uriList: [
'package:material_button/button.dart',
toUri('/home/material_button/test/button_test.dart').toString(),
],
only: true,
);
}
// package/test can see regular and dev dependencies
{
var path = convertPath('/home/test/test/c.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(idList, contains(uriToLibrary[bUri].id));
var path = convertPath('/home/material_button/testing/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:bbb/b.dart',
'package:material_button/button.dart',
],
only: true,
);
_assertHasLibraries(
libraries.context,
uriList: [
'package:material_button_testing/material_button_po.dart',
],
only: true,
);
}
}
test_getLibraries_pub_inner() async {
newFile('/home/aaa/lib/a.dart', content: r'''
class A {}
''');
newFile('/home/bbb/lib/b.dart', content: r'''
class B {}
''');
test_getLibraries_pub() async {
newFile('/home/aaa/lib/a.dart', content: 'class A {}');
newFile('/home/aaa/lib/src/a2.dart', content: 'class A2 {}');
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
newFile('/home/bbb/lib/b.dart', content: 'class B {}');
newFile('/home/bbb/lib/src/b2.dart', content: 'class B2 {}');
newFile('/home/ccc/lib/c.dart', content: 'class C {}');
newFile('/home/ccc/lib/src/c2.dart', content: 'class C2 {}');
newFile('/home/test/pubspec.yaml', content: r'''
name: test
dependencies:
aaa: any
dev_dependencies:
bbb: any
''');
newFile('/home/test/lib/t.dart', content: 'class T {}');
newFile('/home/test/lib/src/t2.dart', content: 'class T2 {}');
newFile('/home/test/bin/t3.dart', content: 'class T3 {}');
newFile('/home/test/test/t4.dart', content: 'class T4 {}');
newFile('/home/test/examples/basic/pubspec.yaml', content: r'''
name: basic
newFile('/home/test/samples/basic/pubspec.yaml', content: r'''
name: test
dependencies:
bbb: any
ccc: any
test: any
''');
newFile('/home/test/samples/basic/lib/s.dart', content: 'class S {}');
newFile('/home/test/lib/test.dart', content: '');
newFile('/home/test/examples/basic/lib/basic.dart', content: '');
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
addTestPackageDependency('ccc', '/home/ccc');
addTestPackageDependency('basic', '/home/test/samples/basic');
var context = tracker.addContext(testAnalysisContext);
await _doAllTrackerWork();
var aUri = 'package:aaa/a.dart';
var bUri = 'package:bbb/b.dart';
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('A'),
], uriStr: aUri);
], uriStr: 'package:aaa/a.dart');
_assertNoLibrary('package:aaa/src/a2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('B'),
], uriStr: bUri);
], uriStr: 'package:bbb/b.dart');
_assertNoLibrary('package:bbb/src/b2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('C'),
], uriStr: 'package:ccc/c.dart');
_assertNoLibrary('package:ccc/src/c2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('T'),
], uriStr: 'package:test/t.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('T2'),
], uriStr: 'package:test/src/t2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('S'),
], uriStr: 'package:basic/s.dart');
// package/lib can see package:aaa
{
var path = convertPath('/home/test/lib/a.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(idList, isNot(contains(uriToLibrary[bUri].id)));
var path = convertPath('/home/test/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
// Note, no `bin/` or `test/` libraries.
// Note, has `lib/src` library.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
],
only: true,
);
}
// examples/basic can see package:bbb
{
var path = convertPath('/home/test/examples/basic/lib/basic.dart');
var idList = context.getLibraries(path);
expect(idList, isNot(contains(uriToLibrary[aUri].id)));
expect(idList, contains(uriToLibrary[bUri].id));
var path = convertPath('/home/test/bin/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:aaa/a.dart',
'package:bbb/b.dart',
],
only: true,
);
// Note, no `test/` libraries.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/bin/t3.dart').toString(),
],
only: true,
);
}
{
var path = convertPath('/home/test/test/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:aaa/a.dart',
'package:bbb/b.dart',
],
only: true,
);
// Note, no `bin/` libraries.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/test/t4.dart').toString(),
],
only: true,
);
}
{
var path = convertPath('/home/test/samples/basic/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.sdk,
uriList: ['dart:core', 'dart:async'],
);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:ccc/c.dart',
'package:test/t.dart',
],
only: true,
);
// Note, no `package:test` libraries.
_assertHasLibraries(
libraries.context,
uriList: [
'package:basic/s.dart',
],
only: true,
);
}
}
@ -391,9 +578,9 @@ class B {}
addTestPackageDependency('aaa', '/home/aaa');
addTestPackageDependency('bbb', '/home/bbb');
newFile('/home/test/lib/test.dart', content: r'''
class C {}
''');
newFile('/home/test/lib/t.dart', content: 'class T {}');
newFile('/home/test/lib/src/t2.dart', content: 'class T2 {}');
newFile('/home/test/test/t3.dart', content: 'class T3 {}');
var context = tracker.addContext(testAnalysisContext);
context.setDependencies({
@ -406,32 +593,67 @@ class C {}
await _doAllTrackerWork();
var aUri = 'package:aaa/a.dart';
var bUri = 'package:bbb/b.dart';
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('A1'),
_ExpectedDeclaration.class_('A2'),
], uriStr: aUri);
], uriStr: 'package:aaa/a.dart');
_assertNoLibrary('package:aaa/src/a2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('B'),
], uriStr: bUri);
], uriStr: 'package:bbb/b.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('T'),
], uriStr: 'package:test/t.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('T2'),
], uriStr: 'package:test/src/t2.dart');
_assertLibraryDeclarations([
_ExpectedDeclaration.class_('T3'),
], uriStr: toUri('/home/test/test/t3.dart').toString());
// package/lib can see only regular dependencies
// `lib/` is configured to see `package:aaa`.
{
var path = convertPath('/home/test/lib/a.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(idList, isNot(contains(uriToLibrary[bUri].id)));
var path = convertPath('/home/test/lib/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
// Not in a package, so all context files are visible.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/test/t3.dart').toString(),
],
only: true,
);
}
// package/bin can see regular and dev dependencies
// `test/` is configured to see `package:aaa` and `package:bbb`.
{
var path = convertPath('/home/test/bin/b.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(idList, contains(uriToLibrary[bUri].id));
var path = convertPath('/home/test/bin/_.dart');
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: [
'package:aaa/a.dart',
'package:bbb/b.dart',
],
only: true,
);
// Not in a package, so all context files are visible.
_assertHasLibraries(
libraries.context,
uriList: [
'package:test/t.dart',
'package:test/src/t2.dart',
toUri('/home/test/test/t3.dart').toString(),
],
only: true,
);
}
}
@ -468,9 +690,12 @@ class C {}
// The package can see package:aaa, but not package:bbb
{
var path = convertPath('/home/test/lib/a.dart');
var idList = context.getLibraries(path);
expect(idList, contains(uriToLibrary[aUri].id));
expect(uriToLibrary[bUri], isNull);
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:aaa/a.dart'],
only: true,
);
}
context.setDependencies({
@ -488,9 +713,12 @@ class C {}
// The package can see package:bbb, but not package:aaa
{
var path = convertPath('/home/test/lib/a.dart');
var idList = context.getLibraries(path);
expect(idList, isNot(contains(uriToLibrary[aUri].id)));
expect(idList, contains(uriToLibrary[bUri].id));
var libraries = context.getLibraries(path);
_assertHasLibraries(
libraries.dependencies,
uriList: ['package:bbb/b.dart'],
only: true,
);
}
}
@ -619,13 +847,7 @@ class A {}
expect(library, isNotNull);
expect(library.declarations, hasLength(expectedDeclarations.length));
for (var expected in expectedDeclarations) {
expect(
library.declarations,
contains(predicate((Declaration d) {
return d.name == expected.name && d.kind == expected.kind;
})),
reason: '$expected',
);
_asyncHasDeclaration(library, expected);
}
}
@ -633,6 +855,16 @@ class A {}
expect(uriToLibrary, isNot(contains(uriStr)));
}
void _asyncHasDeclaration(Library library, _ExpectedDeclaration expected) {
expect(
library.declarations,
contains(predicate((Declaration d) {
return d.name == expected.name && d.kind == expected.kind;
})),
reason: '$expected',
);
}
void _createTracker() {
uriToLibrary.clear();
@ -663,6 +895,16 @@ class A {}
if (times == 0) return new Future.value();
return new Future.delayed(Duration.zero, () => pumpEventQueue(times - 1));
}
static void _assertHasLibraries(List<Library> libraries,
{@required List<String> uriList, bool only = false}) {
var actualUriList = libraries.map((lib) => lib.uri.toString()).toList();
if (only) {
expect(actualUriList, unorderedEquals(uriList));
} else {
expect(actualUriList, containsAll(uriList));
}
}
}
//class _ExpectedLibrary {