blob: 5e2bcd6adc92ffcb88ac8fff3ee9a06ca722bbae [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analyzer.test.src.summary.resynthesize_ast_test;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/link.dart';
import 'package:analyzer/src/summary/prelink.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/summary/summarize_ast.dart';
import 'package:analyzer/src/summary/summarize_elements.dart'
show PackageBundleAssembler;
import 'package:analyzer/task/dart.dart' show PARSED_UNIT;
import 'package:unittest/unittest.dart';
import '../../reflective_tests.dart';
import '../context/abstract_context.dart';
import '../task/strong/inferred_type_test.dart';
import 'resynthesize_test.dart';
import 'summary_common.dart';
main() {
groupSep = ' | ';
runReflectiveTests(ResynthesizeAstTest);
runReflectiveTests(AstInferredTypeTest);
}
@reflectiveTest
class AstInferredTypeTest extends AbstractResynthesizeTest
with _AstResynthesizeTestMixin, InferredTypeMixin {
bool get checkPropagatedTypes {
// AST-based summaries do not yet handle propagated types.
// TODO(paulberry): fix this.
return false;
}
@override
bool get skipBrokenAstInference => true;
@override
void addFile(String content, {String name: '/main.dart'}) {
addLibrarySource(name, content);
}
@override
CompilationUnitElement checkFile(String content) {
Source source = addSource('/main.dart', content);
SummaryResynthesizer resynthesizer = _encodeLibrary(source);
LibraryElementImpl resynthesized = _checkSource(resynthesizer, source);
for (Source otherSource in otherLibrarySources) {
_checkSource(resynthesizer, otherSource);
}
return resynthesized.definingCompilationUnit;
}
@override
void compareLocalVariableElementLists(ExecutableElement resynthesized,
ExecutableElement original, String desc) {
// We don't resynthesize local elements during link.
// So, we should not compare them.
}
@override
DartSdk createDartSdk() => AbstractContextTest.SHARED_STRONG_MOCK_SDK;
@override
AnalysisOptionsImpl createOptions() => new AnalysisOptionsImpl()
..enableGenericMethods = true
..strongMode = true;
@override
@failingTest
void test_blockBodiedLambdas_async_allReturnsAreValues() {
super.test_blockBodiedLambdas_async_allReturnsAreValues();
}
@override
@failingTest
void test_blockBodiedLambdas_async_alReturnsAreFutures() {
super.test_blockBodiedLambdas_async_alReturnsAreFutures();
}
@override
@failingTest
void test_blockBodiedLambdas_async_mixOfValuesAndFutures() {
super.test_blockBodiedLambdas_async_mixOfValuesAndFutures();
}
@override
@failingTest
void test_blockBodiedLambdas_asyncStar() {
super.test_blockBodiedLambdas_asyncStar();
}
@override
@failingTest
void test_blockBodiedLambdas_basic_topLevel() {
super.test_blockBodiedLambdas_basic_topLevel();
}
@override
@failingTest
void test_blockBodiedLambdas_doesNotInferBottom_async() {
super.test_blockBodiedLambdas_doesNotInferBottom_async();
}
@override
@failingTest
void test_blockBodiedLambdas_doesNotInferBottom_asyncStar() {
super.test_blockBodiedLambdas_doesNotInferBottom_asyncStar();
}
@override
@failingTest
void test_blockBodiedLambdas_doesNotInferBottom_sync() {
super.test_blockBodiedLambdas_doesNotInferBottom_sync();
}
@override
@failingTest
void test_blockBodiedLambdas_doesNotInferBottom_syncStar() {
super.test_blockBodiedLambdas_doesNotInferBottom_syncStar();
}
@override
@failingTest
void test_blockBodiedLambdas_downwardsIncompatibleWithUpwardsInference() {
super.test_blockBodiedLambdas_downwardsIncompatibleWithUpwardsInference();
}
@override
@failingTest
void test_blockBodiedLambdas_LUB_topLevel() {
super.test_blockBodiedLambdas_LUB_topLevel();
}
@override
@failingTest
void test_blockBodiedLambdas_nestedLambdas() {
super.test_blockBodiedLambdas_nestedLambdas();
}
@override
@failingTest
void test_blockBodiedLambdas_noReturn() {
super.test_blockBodiedLambdas_noReturn();
}
@override
@failingTest
void test_blockBodiedLambdas_syncStar() {
super.test_blockBodiedLambdas_syncStar();
}
@override
@failingTest
void test_canInferAlsoFromStaticAndInstanceFieldsFlagOn() {
super.test_canInferAlsoFromStaticAndInstanceFieldsFlagOn();
}
@override
@failingTest
void test_downwardsInferenceAnnotations() {
super.test_downwardsInferenceAnnotations();
}
@override
@failingTest
void test_downwardsInferenceAsyncAwait() {
super.test_downwardsInferenceAsyncAwait();
}
@override
@failingTest
void test_downwardsInferenceForEach() {
super.test_downwardsInferenceForEach();
}
@override
@failingTest
void test_downwardsInferenceOnFunctionOfTUsingTheT() {
super.test_downwardsInferenceOnFunctionOfTUsingTheT();
}
@override
@failingTest
void test_downwardsInferenceOnGenericFunctionExpressions() {
super.test_downwardsInferenceOnGenericFunctionExpressions();
}
@override
@failingTest
void test_downwardsInferenceYieldYieldStar() {
super.test_downwardsInferenceYieldYieldStar();
}
@override
@failingTest
void test_genericMethods_inferJSBuiltin() {
super.test_genericMethods_inferJSBuiltin();
}
void test_infer_extractIndex_custom() {
var unit = checkFile('''
class A {
String operator [](_) => null;
}
var a = new A();
var b = a[0];
''');
expect(unit.topLevelVariables[1].type.toString(), 'String');
}
void test_infer_extractIndex_fromList() {
var unit = checkFile('''
var a = <int>[1, 2, 3];
var b = a[0];
''');
expect(unit.topLevelVariables[1].type.toString(), 'int');
}
void test_infer_extractIndex_fromMap() {
var unit = checkFile('''
var a = <int, double>{};
var b = a[0];
''');
expect(unit.topLevelVariables[1].type.toString(), 'double');
}
void test_infer_extractProperty_getter() {
checkFile(r'''
var a = 1.isEven;
var b = 2.isNaN;
var c = 3.foo;
var d = foo.bar;
''');
}
void test_infer_extractProperty_method() {
checkFile(r'''
var a = 1.round;
''');
}
void test_infer_invokeConstructor_factoryRedirected() {
checkFile(r'''
class A {
factory A() = B;
}
class B implements A {}
var a = new A();
''');
}
void test_infer_invokeConstructor_named() {
checkFile(r'''
class A {
A.aaa();
}
class B<K, V> {
B.bbb();
}
var a = new A.aaa();
var b1 = new B.bbb();
var b2 = new B<int, String>.bbb();
var b3 = new B<List<int>, Map<List<int>, Set<String>>>.bbb();
''');
}
void test_infer_invokeConstructor_named_importedWithPrefix() {
addFile(
r'''
class A {
A.aaa();
}
class B<K, V> {
B.bbb();
}
''',
name: '/a.dart');
checkFile(r'''
import 'a.dart' as p;
var a = new p.A.aaa();
var b1 = new p.B.bbb();
var b2 = new p.B<int, String>.bbb();
''');
}
void test_infer_invokeConstructor_unnamed() {
checkFile(r'''
class A {
A();
}
class B<T> {
B();
}
var a = new A();
var b1 = new B();
var b2 = new B<int>();
''');
}
void test_infer_invokeConstructor_unnamed_synthetic() {
checkFile(r'''
class A {}
class B<T> {}
var a = new A();
var b1 = new B();
var b2 = new B<int>();
''');
}
@override
@failingTest
void test_inferCorrectlyOnMultipleVariablesDeclaredTogether() {
super.test_inferCorrectlyOnMultipleVariablesDeclaredTogether();
}
@override
@failingTest
void test_inferenceInCyclesIsDeterministic() {
super.test_inferenceInCyclesIsDeterministic();
}
@override
@failingTest
void test_inferFromRhsOnlyIfItWontConflictWithOverriddenFields() {
super.test_inferFromRhsOnlyIfItWontConflictWithOverriddenFields();
}
@override
@failingTest
void test_inferTypesOnGenericInstantiations_4() {
super.test_inferTypesOnGenericInstantiations_4();
}
@override
@failingTest
void test_inferTypesOnGenericInstantiations_5() {
super.test_inferTypesOnGenericInstantiations_5();
}
@override
@failingTest
void test_inferTypesOnGenericInstantiationsInLibraryCycle() {
super.test_inferTypesOnGenericInstantiationsInLibraryCycle();
}
void test_invokeMethod_notGeneric_genericClass() {
var unit = checkFile(r'''
class C<T> {
T m(int a, {String b, T c}) => null;
}
var v = new C<double>().m(1, b: 'bbb', c: 2.0);
''');
expect(unit.topLevelVariables[0].type.toString(), 'double');
}
void test_invokeMethod_notGeneric_notGenericClass() {
var unit = checkFile(r'''
class C {
int m(int a, {String b, int c}) => null;
}
var v = new C().m(1, b: 'bbb', c: 2.0);
''');
expect(unit.topLevelVariables[0].type.toString(), 'int');
}
@override
@failingTest
void test_listLiteralsShouldNotInferBottom() {
super.test_listLiteralsShouldNotInferBottom();
}
@override
@failingTest
void test_mapLiteralsShouldNotInferBottom() {
super.test_mapLiteralsShouldNotInferBottom();
}
@override
@failingTest
void test_nullLiteralShouldNotInferAsBottom() {
super.test_nullLiteralShouldNotInferAsBottom();
}
LibraryElementImpl _checkSource(
SummaryResynthesizer resynthesizer, Source source) {
LibraryElementImpl resynthesized =
resynthesizer.getLibraryElement(source.uri.toString());
LibraryElementImpl original = context.computeLibraryElement(source);
checkLibraryElements(original, resynthesized);
return resynthesized;
}
}
@reflectiveTest
class ResynthesizeAstTest extends ResynthesizeTest
with _AstResynthesizeTestMixin {
@override
bool get checkPropagatedTypes => false;
@override
void checkLibrary(String text,
{bool allowErrors: false, bool dumpSummaries: false}) {
Source source = addTestSource(text);
LibraryElementImpl resynthesized = _encodeDecodeLibraryElement(source);
LibraryElementImpl original = context.computeLibraryElement(source);
checkLibraryElements(original, resynthesized);
}
@override
DartSdk createDartSdk() => AbstractContextTest.SHARED_MOCK_SDK;
@override
TestSummaryResynthesizer encodeDecodeLibrarySource(Source source) {
return _encodeLibrary(source);
}
@override
@failingTest
void test_constructor_initializers_field_notConst() {
super.test_constructor_initializers_field_notConst();
}
@override
@failingTest
void test_inferred_function_type_in_generic_class_constructor() {
super.test_inferred_function_type_in_generic_class_constructor();
}
@override
@failingTest
void test_metadata_constructor_call_named() {
super.test_metadata_constructor_call_named();
}
@override
@failingTest
void test_metadata_constructor_call_named_prefixed() {
super.test_metadata_constructor_call_named_prefixed();
}
@override
@failingTest
void test_metadata_constructor_call_unnamed() {
super.test_metadata_constructor_call_unnamed();
}
@override
@failingTest
void test_metadata_constructor_call_with_args() {
super.test_metadata_constructor_call_with_args();
}
@override
@failingTest
void test_type_reference_to_import_part_in_subdir() {
super.test_type_reference_to_import_part_in_subdir();
}
}
/**
* Abstract mixin for serializing ASTs and resynthesizing elements from it.
*/
abstract class _AstResynthesizeTestMixin {
final Set<Source> serializedSources = new Set<Source>();
final PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
final Map<String, UnlinkedUnitBuilder> uriToUnit =
<String, UnlinkedUnitBuilder>{};
AnalysisContext get context;
LibraryElementImpl _encodeDecodeLibraryElement(Source source) {
SummaryResynthesizer resynthesizer = _encodeLibrary(source);
return resynthesizer.getLibraryElement(source.uri.toString());
}
TestSummaryResynthesizer _encodeLibrary(Source source) {
_serializeLibrary(source);
PackageBundle bundle =
new PackageBundle.fromBuffer(bundleAssembler.assemble().toBuffer());
Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
String uri = bundle.unlinkedUnitUris[i];
unlinkedSummaries[uri] = bundle.unlinkedUnits[i];
}
LinkedLibrary getDependency(String absoluteUri) {
Map<String, LinkedLibrary> sdkLibraries =
SerializedMockSdk.instance.uriToLinkedLibrary;
LinkedLibrary linkedLibrary = sdkLibraries[absoluteUri];
if (linkedLibrary == null) {
fail('Linker unexpectedly requested LinkedLibrary for "$absoluteUri".'
' Libraries available: ${sdkLibraries.keys}');
}
return linkedLibrary;
}
UnlinkedUnit getUnit(String absoluteUri) {
UnlinkedUnit unit = uriToUnit[absoluteUri] ??
SerializedMockSdk.instance.uriToUnlinkedUnit[absoluteUri];
if (unit == null) {
fail('Linker unexpectedly requested unit for "$absoluteUri".');
}
return unit;
}
Set<String> nonSdkLibraryUris = context.sources
.where((Source source) =>
!source.isInSystemLibrary &&
context.computeKindOf(source) == SourceKind.LIBRARY)
.map((Source source) => source.uri.toString())
.toSet();
Map<String, LinkedLibrary> linkedSummaries = link(nonSdkLibraryUris,
getDependency, getUnit, context.analysisOptions.strongMode);
return new TestSummaryResynthesizer(
null,
context,
new Map<String, UnlinkedUnit>()
..addAll(SerializedMockSdk.instance.uriToUnlinkedUnit)
..addAll(unlinkedSummaries),
new Map<String, LinkedLibrary>()
..addAll(SerializedMockSdk.instance.uriToLinkedLibrary)
..addAll(linkedSummaries));
}
UnlinkedUnit _getUnlinkedUnit(Source source) {
String uriStr = source.uri.toString();
{
UnlinkedUnit unlinkedUnitInSdk =
SerializedMockSdk.instance.uriToUnlinkedUnit[uriStr];
if (unlinkedUnitInSdk != null) {
return unlinkedUnitInSdk;
}
}
return uriToUnit.putIfAbsent(uriStr, () {
CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
bundleAssembler.addUnlinkedUnit(source, unlinkedUnit);
return unlinkedUnit;
});
}
void _serializeLibrary(Source librarySource) {
if (librarySource.isInSystemLibrary) {
return;
}
if (!serializedSources.add(librarySource)) {
return;
}
Source resolveRelativeUri(String relativeUri) {
Source resolvedSource =
context.sourceFactory.resolveUri(librarySource, relativeUri);
if (resolvedSource == null) {
throw new StateError('Could not resolve $relativeUri in the context of '
'$librarySource (${librarySource.runtimeType})');
}
return resolvedSource;
}
UnlinkedUnit getPart(String relativeUri) {
return _getUnlinkedUnit(resolveRelativeUri(relativeUri));
}
UnlinkedPublicNamespace getImport(String relativeUri) {
return getPart(relativeUri).publicNamespace;
}
UnlinkedUnit definingUnit = _getUnlinkedUnit(librarySource);
LinkedLibraryBuilder linkedLibrary =
prelink(definingUnit, getPart, getImport);
linkedLibrary.dependencies.skip(1).forEach((LinkedDependency d) {
_serializeLibrary(resolveRelativeUri(d.uri));
});
}
}