Add BazelResultProvider for on-demand packages loading.

R=brianwilkerson@google.com, paulberry@google.com
BUG=

Review URL: https://codereview.chromium.org/2386463002 .
This commit is contained in:
Konstantin Shcheglov 2016-09-30 08:55:59 -07:00
parent 8c4db65326
commit 33ffb7a6ae
2 changed files with 174 additions and 9 deletions

View file

@ -26,6 +26,49 @@ import 'package:meta/meta.dart';
*/
typedef Folder GetOutputFolder(Uri absoluteUri);
/**
* Load linked packages on demand from [SummaryProvider].
*/
class BazelResultProvider extends ResynthesizerResultProvider {
final SummaryDataStore dataStore;
final SummaryProvider summaryProvider;
final Map<Source, bool> sourceToSuccessMap = <Source, bool>{};
final Set<Package> addedPackages = new Set<Package>();
factory BazelResultProvider(SummaryProvider summaryProvider) {
SummaryDataStore dataStore = new SummaryDataStore(const <String>[]);
return new BazelResultProvider._(dataStore, summaryProvider);
}
BazelResultProvider._(
SummaryDataStore dataStore, SummaryProvider summaryProvider)
: dataStore = dataStore,
summaryProvider = summaryProvider,
super(summaryProvider.context, dataStore) {
AnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
createResynthesizer(sdkContext, sdkContext.typeProvider);
}
@override
bool hasResultsForSource(Source source) {
return sourceToSuccessMap.putIfAbsent(source, () {
List<Package> packages = summaryProvider.getLinkedPackages(source);
if (packages == null) {
return false;
}
for (Package package in packages) {
if (addedPackages.add(package)) {
dataStore.addBundle(null, package.unlinked);
dataStore.addBundle(null, package.linked);
}
}
String uriString = source.uri.toString();
return resynthesizer.hasLibrarySummary(uriString);
});
}
}
/**
* Information about a Dart package in Bazel.
*/

View file

@ -4,8 +4,10 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
@ -16,6 +18,7 @@ import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/summarize_ast.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
import 'package:analyzer/src/util/fast_uri.dart';
import 'package:analyzer/task/dart.dart';
import 'package:path/path.dart' as pathos;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@ -25,6 +28,7 @@ import '../context/abstract_context.dart';
main() {
initializeTestEnvironment();
defineReflectiveTests(BazelResultProviderTest);
defineReflectiveTests(SummaryProviderTest);
}
@ -32,23 +36,127 @@ const OUT_ROOT = '$SRC_ROOT/bazel-bin';
const SRC_ROOT = '/company/src/user/project/root';
@reflectiveTest
class SummaryProviderTest extends AbstractContextTest {
class BazelResultProviderTest extends _BaseTest {
BazelResultProvider provider;
@override
void setUp() {
super.setUp();
provider = new BazelResultProvider(
new SummaryProvider(resourceProvider, _getOutputFolder, context));
}
test_failure_inconsistent_directDependency() {
_setComponentFile('aaa', 'a.dart', 'class A {}');
_setComponentFile(
'bbb',
'b.dart',
r'''
import 'package:components.aaa/a.dart';
class B extends A {}
''');
_writeUnlinkedBundle('components.aaa');
_writeUnlinkedBundle('components.bbb');
_setComponentFile('aaa', 'a.dart', 'class A2 {}');
// The 'aaa' unlinked bundle in inconsistent, so 'bbb' linking fails.
Source source = _resolveUri('package:components.bbb/b.dart');
CacheEntry entry = context.getCacheEntry(source);
expect(provider.compute(entry, LIBRARY_ELEMENT), isFalse);
}
test_failure_missingDirectDependency() {
_setComponentFile('aaa', 'a.dart', 'class A {}');
_setComponentFile(
'bbb',
'b.dart',
r'''
import 'package:components.aaa/a.dart';
class B extends A {}
''');
_writeUnlinkedBundle('components.bbb');
// We cannot find 'aaa' bundle, so 'bbb' linking fails.
Source source = _resolveUri('package:components.bbb/b.dart');
CacheEntry entry = context.getCacheEntry(source);
expect(provider.compute(entry, LIBRARY_ELEMENT), isFalse);
}
test_success_withoutDependencies() {
_setComponentFile('aaa', 'a.dart', 'class A {}');
_writeUnlinkedBundle('components.aaa');
// Resynthesize 'aaa' library.
Source source = _resolveUri('package:components.aaa/a.dart');
LibraryElement library = _resynthesizeLibrary(source);
List<ClassElement> types = library.definingCompilationUnit.types;
expect(types, hasLength(1));
expect(types.single.name, 'A');
}
test_withDependency_import() {
_setComponentFile('aaa', 'a.dart', 'class A {}');
_setComponentFile(
'bbb',
'b.dart',
r'''
import 'package:components.aaa/a.dart';
class B extends A {}
''');
_writeUnlinkedBundle('components.aaa');
_writeUnlinkedBundle('components.bbb');
// Prepare sources.
Source sourceA = _resolveUri('package:components.aaa/a.dart');
Source sourceB = _resolveUri('package:components.bbb/b.dart');
// Resynthesize 'bbb' library.
LibraryElement libraryB = _resynthesizeLibrary(sourceB);
List<ClassElement> types = libraryB.definingCompilationUnit.types;
expect(types, hasLength(1));
ClassElement typeB = types.single;
expect(typeB.name, 'B');
expect(typeB.supertype.name, 'A');
// The LibraryElement for 'aaa' is not created at all.
expect(context.getResult(sourceA, LIBRARY_ELEMENT), isNull);
// But we can resynthesize it, and it's the same as from 'bbb'.
expect(provider.compute(context.getCacheEntry(sourceA), LIBRARY_ELEMENT),
isTrue);
LibraryElement libraryA = context.getResult(sourceA, LIBRARY_ELEMENT);
expect(libraryA, isNotNull);
expect(typeB.supertype.element.library, same(libraryA));
}
LibraryElement _resynthesizeLibrary(Source source) {
CacheEntry entry = context.getCacheEntry(source);
expect(provider.compute(entry, LIBRARY_ELEMENT), isTrue);
return context.getResult(source, LIBRARY_ELEMENT);
}
}
@reflectiveTest
class SummaryProviderTest extends _BaseTest {
SummaryProvider manager;
@override
void setUp() {
super.setUp();
// Include a 'package' URI resolver.
sourceFactory = new SourceFactory(<UriResolver>[
sdkResolver,
resourceResolver,
new _TestPackageResolver(resourceProvider)
], null, resourceProvider);
context.sourceFactory = sourceFactory;
// Create a new SummaryProvider instance.
manager = new SummaryProvider(resourceProvider, _getOutputFolder, context);
}
test_getLinkedPackages_null_inconsistent_directDependency() {
_setComponentFile('aaa', 'a.dart', 'class A {}');
_setComponentFile(
'bbb',
'b.dart',
r'''
import 'package:components.aaa/a.dart';
class B extends A {}
''');
_writeUnlinkedBundle('components.aaa');
_writeUnlinkedBundle('components.bbb');
_setComponentFile('aaa', 'a.dart', 'class A2 {}');
// The 'aaa' unlinked bundle in inconsistent, so 'bbb' linking fails.
Source source = _resolveUri('package:components.bbb/b.dart');
List<Package> packages = manager.getLinkedPackages(source);
expect(packages, isNull);
}
test_getLinkedPackages_null_missingBundle() {
_setComponentFile('aaa', 'a.dart', 'class A {}');
// We don't write 'aaa', so we cannot get its package.
@ -210,6 +318,20 @@ class C extends B {}
expect(manager.getUnlinkedForUri(source1.uri), isNull);
expect(manager.getUnlinkedForUri(source2.uri), isNull);
}
}
class _BaseTest extends AbstractContextTest {
@override
void setUp() {
super.setUp();
// Include a 'package' URI resolver.
sourceFactory = new SourceFactory(<UriResolver>[
sdkResolver,
resourceResolver,
new _TestPackageResolver(resourceProvider)
], null, resourceProvider);
context.sourceFactory = sourceFactory;
}
Folder _getOutputFolder(Uri absoluteUri) {
if (absoluteUri.scheme == 'package') {