Refactor summary resynthesis tests in preparation for using the one-phase summary API.
This CL refactors the summary resynthesis tests similar to how
05ab41c99b0972e75086ecbc3f617ba9a36da372 refactored the summary
generation tests. It introduces the following classes:
- The interface `ResynthesizeTestStrategy`, defining the methods that
can be invoked by tests of summary resynthesis.
- An implementation of that interface:
`ResynthesizeTestStrategyTwoPhase`. This drives the summary
mechanism using the old two-phase summary API.
- Mixin classes `ExprBuilderTestCases` and `ResynthesizeTestCases`
containing the test cases themselves.
- Mixin classes `ExprBuilderTestHelpers` and `ResynthesizeTestHelpers`
containing helper methods used by the test cases.
There should be no functional change introduced by this CL, only code
motion.
Change-Id: Ifb84d4d2d8fa17bbc32b833b1f56af7e1217b5ae
Reviewed-on: https://dart-review.googlesource.com/75124
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/test/src/summary/expr_builder_test.dart b/pkg/analyzer/test/src/summary/expr_builder_test.dart
index ef991be..c17d7f8 100644
--- a/pkg/analyzer/test/src/summary/expr_builder_test.dart
+++ b/pkg/analyzer/test/src/summary/expr_builder_test.dart
@@ -11,9 +11,8 @@
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import '../abstract_single_unit.dart';
-import 'resynthesize_ast_test.dart';
import 'resynthesize_common.dart';
+import 'test_strategies.dart';
main() {
defineReflectiveSuite(() {
@@ -22,100 +21,13 @@
}
@reflectiveTest
-class ExprBuilderTest extends AbstractSingleUnitTest
- with AstSerializeTestMixin {
- @override
- bool get allowMissingFiles => false;
+class ExprBuilderTest extends ResynthesizeTestStrategyTwoPhase
+ with ExprBuilderTestCases, ExprBuilderTestHelpers {}
- Expression buildConstructorInitializer(String sourceText,
- {String className: 'C',
- String initializerName: 'x',
- bool requireValidConst: false}) {
- var resynthesizer = encodeSource(sourceText);
- var library = resynthesizer.getLibraryElement(testSource.uri.toString());
- var c = library.getType(className);
- var constructor = c.unnamedConstructor as ConstructorElementImpl;
- var serializedExecutable = constructor.serializedExecutable;
- var x = serializedExecutable.constantInitializers
- .singleWhere((i) => i.name == initializerName);
- return buildExpression(resynthesizer, constructor, x.expression,
- serializedExecutable.localFunctions,
- requireValidConst: requireValidConst);
- }
-
- Expression buildExpression(
- TestSummaryResynthesizer resynthesizer,
- ElementImpl context,
- UnlinkedExpr unlinkedExpr,
- List<UnlinkedExecutable> localFunctions,
- {bool requireValidConst: false}) {
- var library = resynthesizer.getLibraryElement(testSource.uri.toString());
- var unit = library.definingCompilationUnit as CompilationUnitElementImpl;
- var unitResynthesizerContext =
- unit.resynthesizerContext as SummaryResynthesizerContext;
- var unitResynthesizer = unitResynthesizerContext.unitResynthesizer;
- var exprBuilder = new ExprBuilder(unitResynthesizer, context, unlinkedExpr,
- requireValidConst: requireValidConst, localFunctions: localFunctions);
- return exprBuilder.build();
- }
-
- Expression buildTopLevelVariable(String sourceText,
- {String variableName: 'x', bool requireValidConst: false}) {
- var resynthesizer = encodeSource(sourceText);
- var library = resynthesizer.getLibraryElement(testSource.uri.toString());
- var unit = library.definingCompilationUnit as CompilationUnitElementImpl;
- TopLevelVariableElementImpl x =
- unit.topLevelVariables.singleWhere((e) => e.name == variableName);
- return buildExpression(
- resynthesizer,
- x,
- x.unlinkedVariableForTesting.initializer.bodyExpr,
- x.unlinkedVariableForTesting.initializer.localFunctions,
- requireValidConst: requireValidConst);
- }
-
- void checkCompoundAssignment(String exprText) {
- checkSimpleExpression(exprText, extraDeclarations: 'var y;');
- }
-
- void checkConstructorInitializer(String sourceText, String expectedText,
- {String className: 'C',
- String initializerName: 'x',
- bool requireValidConst: false}) {
- Expression expr = buildConstructorInitializer(sourceText,
- className: className,
- initializerName: initializerName,
- requireValidConst: requireValidConst);
- expect(expr.toString(), expectedText);
- }
-
- void checkInvalidConst(String expressionText) {
- checkTopLevelVariable('var x = $expressionText;', 'null',
- requireValidConst: true);
- }
-
- Expression checkSimpleExpression(String expressionText,
- {String expectedText,
- String extraDeclarations: '',
- bool requireValidConst: false}) {
- return checkTopLevelVariable('var x = $expressionText;\n$extraDeclarations',
- expectedText ?? expressionText,
- requireValidConst: requireValidConst);
- }
-
- Expression checkTopLevelVariable(String sourceText, String expectedText,
- {String variableName: 'x', bool requireValidConst: false}) {
- Expression expr = buildTopLevelVariable(sourceText,
- variableName: variableName, requireValidConst: requireValidConst);
- expect(expr.toString(), expectedText);
- return expr;
- }
-
- TestSummaryResynthesizer encodeSource(String text) {
- var source = addTestSource(text);
- return encodeLibrary(source);
- }
-
+/// Mixin containing test cases exercising the [ExprBuilder]. Intended to be
+/// applied to a class implementing [ResynthesizeTestStrategy], along with the
+/// mixin [ExprBuilderTestHelpers].
+abstract class ExprBuilderTestCases implements ExprBuilderTestHelpers {
void test_add() {
checkSimpleExpression('0 + 1');
}
@@ -565,3 +477,96 @@
checkSimpleExpression('0 is! num', expectedText: '!(0 is num)');
}
}
+
+/// Mixin containing helper methods for testing the [ExprBuilder]. Intended to
+/// be applied to a class implementing [ResynthesizeTestStrategy].
+abstract class ExprBuilderTestHelpers implements ResynthesizeTestStrategy {
+ Expression buildConstructorInitializer(String sourceText,
+ {String className: 'C',
+ String initializerName: 'x',
+ bool requireValidConst: false}) {
+ var resynthesizer = encodeSource(sourceText);
+ var library = resynthesizer.getLibraryElement(testSource.uri.toString());
+ var c = library.getType(className);
+ var constructor = c.unnamedConstructor as ConstructorElementImpl;
+ var serializedExecutable = constructor.serializedExecutable;
+ var x = serializedExecutable.constantInitializers
+ .singleWhere((i) => i.name == initializerName);
+ return buildExpression(resynthesizer, constructor, x.expression,
+ serializedExecutable.localFunctions,
+ requireValidConst: requireValidConst);
+ }
+
+ Expression buildExpression(
+ TestSummaryResynthesizer resynthesizer,
+ ElementImpl context,
+ UnlinkedExpr unlinkedExpr,
+ List<UnlinkedExecutable> localFunctions,
+ {bool requireValidConst: false}) {
+ var library = resynthesizer.getLibraryElement(testSource.uri.toString());
+ var unit = library.definingCompilationUnit as CompilationUnitElementImpl;
+ var unitResynthesizerContext =
+ unit.resynthesizerContext as SummaryResynthesizerContext;
+ var unitResynthesizer = unitResynthesizerContext.unitResynthesizer;
+ var exprBuilder = new ExprBuilder(unitResynthesizer, context, unlinkedExpr,
+ requireValidConst: requireValidConst, localFunctions: localFunctions);
+ return exprBuilder.build();
+ }
+
+ Expression buildTopLevelVariable(String sourceText,
+ {String variableName: 'x', bool requireValidConst: false}) {
+ var resynthesizer = encodeSource(sourceText);
+ var library = resynthesizer.getLibraryElement(testSource.uri.toString());
+ var unit = library.definingCompilationUnit as CompilationUnitElementImpl;
+ TopLevelVariableElementImpl x =
+ unit.topLevelVariables.singleWhere((e) => e.name == variableName);
+ return buildExpression(
+ resynthesizer,
+ x,
+ x.unlinkedVariableForTesting.initializer.bodyExpr,
+ x.unlinkedVariableForTesting.initializer.localFunctions,
+ requireValidConst: requireValidConst);
+ }
+
+ void checkCompoundAssignment(String exprText) {
+ checkSimpleExpression(exprText, extraDeclarations: 'var y;');
+ }
+
+ void checkConstructorInitializer(String sourceText, String expectedText,
+ {String className: 'C',
+ String initializerName: 'x',
+ bool requireValidConst: false}) {
+ Expression expr = buildConstructorInitializer(sourceText,
+ className: className,
+ initializerName: initializerName,
+ requireValidConst: requireValidConst);
+ expect(expr.toString(), expectedText);
+ }
+
+ void checkInvalidConst(String expressionText) {
+ checkTopLevelVariable('var x = $expressionText;', 'null',
+ requireValidConst: true);
+ }
+
+ Expression checkSimpleExpression(String expressionText,
+ {String expectedText,
+ String extraDeclarations: '',
+ bool requireValidConst: false}) {
+ return checkTopLevelVariable('var x = $expressionText;\n$extraDeclarations',
+ expectedText ?? expressionText,
+ requireValidConst: requireValidConst);
+ }
+
+ Expression checkTopLevelVariable(String sourceText, String expectedText,
+ {String variableName: 'x', bool requireValidConst: false}) {
+ Expression expr = buildTopLevelVariable(sourceText,
+ variableName: variableName, requireValidConst: requireValidConst);
+ expect(expr.toString(), expectedText);
+ return expr;
+ }
+
+ TestSummaryResynthesizer encodeSource(String text) {
+ var source = addTestSource(text);
+ return encodeLibrary(source);
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index f49374a..c15af1e 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -2,30 +2,8 @@
// 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/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/error/error.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/src/task/api/dart.dart' show PARSED_UNIT;
-import 'package:analyzer/src/task/api/general.dart';
-import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import '../context/abstract_context.dart';
import 'element_text.dart';
import 'resynthesize_common.dart';
import 'test_strategies.dart';
@@ -44,129 +22,9 @@
}
}
-/// Mixin for serializing ASTs during testing.
-abstract class AstSerializeTestMixin
- implements _AstSerializeTestMixinInterface {
- final Set<Source> serializedSources = new Set<Source>();
- PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
- final Map<String, UnlinkedUnitBuilder> uriToUnit =
- <String, UnlinkedUnitBuilder>{};
-
- AnalysisContext get context;
-
- 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 && !allowMissingFiles) {
- 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 && !allowMissingFiles) {
- fail('Linker unexpectedly requested unit for "$absoluteUri".');
- }
- return unit;
- }
-
- Set<String> nonSdkLibraryUris = serializedSources
- .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.declaredVariables.get);
-
- return new TestSummaryResynthesizer(
- context,
- new Map<String, UnlinkedUnit>()
- ..addAll(SerializedMockSdk.instance.uriToUnlinkedUnit)
- ..addAll(unlinkedSummaries),
- new Map<String, LinkedLibrary>()
- ..addAll(SerializedMockSdk.instance.uriToLinkedLibrary)
- ..addAll(linkedSummaries),
- allowMissingFiles);
- }
-
- UnlinkedUnit _getUnlinkedUnit(Source source) {
- if (source == null) {
- return new UnlinkedUnitBuilder();
- }
-
- String uriStr = source.uri.toString();
- {
- UnlinkedUnit unlinkedUnitInSdk =
- SerializedMockSdk.instance.uriToUnlinkedUnit[uriStr];
- if (unlinkedUnitInSdk != null) {
- return unlinkedUnitInSdk;
- }
- }
- return uriToUnit.putIfAbsent(uriStr, () {
- int modificationTime = context.computeResult(source, MODIFICATION_TIME);
- if (modificationTime < 0) {
- // Source does not exist.
- if (!allowMissingFiles) {
- fail('Unexpectedly tried to get unlinked summary for $source');
- }
- return null;
- }
- CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
- UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
- bundleAssembler.addUnlinkedUnit(source, unlinkedUnit);
- return unlinkedUnit;
- });
- }
-
- void _serializeLibrary(Source librarySource) {
- if (librarySource == null || librarySource.isInSystemLibrary) {
- return;
- }
- if (!serializedSources.add(librarySource)) {
- return;
- }
-
- UnlinkedUnit getPart(String absoluteUri) {
- Source source = context.sourceFactory.forUri(absoluteUri);
- return _getUnlinkedUnit(source);
- }
-
- UnlinkedPublicNamespace getImport(String relativeUri) {
- return getPart(relativeUri)?.publicNamespace;
- }
-
- UnlinkedUnit definingUnit = _getUnlinkedUnit(librarySource);
- if (definingUnit != null) {
- LinkedLibraryBuilder linkedLibrary = prelink(librarySource.uri.toString(),
- definingUnit, getPart, getImport, context.declaredVariables.get);
- linkedLibrary.dependencies.skip(1).forEach((LinkedDependency d) {
- Source source = context.sourceFactory.forUri(d.uri);
- _serializeLibrary(source);
- });
- }
- }
-}
-
@reflectiveTest
-class ResynthesizeAstStrongTest extends _ResynthesizeAstTest {
+class ResynthesizeAstStrongTest extends ResynthesizeTestStrategyTwoPhase
+ with ResynthesizeTestCases, ResynthesizeTestHelpers {
@failingTest // See dartbug.com/32290
test_const_constructor_inferred_args() =>
super.test_const_constructor_inferred_args();
@@ -201,164 +59,3 @@
await super.test_syntheticFunctionType_withArguments();
}
}
-
-/**
- * Abstract mixin for serializing ASTs and resynthesizing elements from it.
- */
-abstract class _AstResynthesizeTestMixin
- implements _AstSerializeTestMixinInterface {
- AnalysisContext get context;
-
- TestSummaryResynthesizer encodeLibrary(Source source);
-
- LibraryElementImpl _encodeDecodeLibraryElement(Source source) {
- SummaryResynthesizer resynthesizer = encodeLibrary(source);
- return resynthesizer.getLibraryElement(source.uri.toString());
- }
-}
-
-/**
- * Interface that [_AstSerializeTestMixin] requires of classes it's mixed
- * into. We can't place the getter below into [_AstSerializeTestMixin]
- * directly, because then it would be overriding a field at the site where the
- * mixin is instantiated.
- */
-abstract class _AstSerializeTestMixinInterface {
- /**
- * A test should return `true` to indicate that a missing file at the time of
- * summary resynthesis shouldn't trigger an error.
- */
- bool get allowMissingFiles;
-}
-
-abstract class _ResynthesizeAstTest extends ResynthesizeTest
- with _AstResynthesizeTestMixin, AstSerializeTestMixin {
- bool get shouldCompareLibraryElements;
-
- @override
- Future<LibraryElementImpl> checkLibrary(String text,
- {bool allowErrors: false, bool dumpSummaries: false}) async {
- Source source = addTestSource(text);
- LibraryElementImpl resynthesized = _encodeDecodeLibraryElement(source);
- LibraryElementImpl original = context.computeLibraryElement(source);
- if (!allowErrors) {
- List<AnalysisError> errors = context.computeErrors(source);
- if (errors.where((e) => e.message.startsWith('unused')).isNotEmpty) {
- fail('Analysis errors: $errors');
- }
- }
- if (shouldCompareLibraryElements) {
- checkLibraryElements(original, resynthesized);
- }
- return resynthesized;
- }
-
- @override
- DartSdk createDartSdk() => AbstractContextTest.SHARED_MOCK_SDK;
-
- @override
- AnalysisOptionsImpl createOptions() {
- return super.createOptions()
- ..previewDart2 = true
- ..isMixinSupportEnabled = true;
- }
-
- test_getElement_constructor_named() async {
- String text = 'class C { C.named(); }';
- Source source = addLibrarySource('/test.dart', text);
- ConstructorElement original = context
- .computeLibraryElement(source)
- .getType('C')
- .getNamedConstructor('named');
- expect(original, isNotNull);
- ConstructorElement resynthesized = _validateGetElement(text, original);
- compareConstructorElements(resynthesized, original, 'C.constructor named');
- }
-
- test_getElement_constructor_unnamed() async {
- String text = 'class C { C(); }';
- Source source = addLibrarySource('/test.dart', text);
- ConstructorElement original =
- context.computeLibraryElement(source).getType('C').unnamedConstructor;
- expect(original, isNotNull);
- ConstructorElement resynthesized = _validateGetElement(text, original);
- compareConstructorElements(resynthesized, original, 'C.constructor');
- }
-
- test_getElement_field() async {
- String text = 'class C { var f; }';
- Source source = addLibrarySource('/test.dart', text);
- FieldElement original =
- context.computeLibraryElement(source).getType('C').getField('f');
- expect(original, isNotNull);
- FieldElement resynthesized = _validateGetElement(text, original);
- compareFieldElements(resynthesized, original, 'C.field f');
- }
-
- test_getElement_getter() async {
- String text = 'class C { get f => null; }';
- Source source = addLibrarySource('/test.dart', text);
- PropertyAccessorElement original =
- context.computeLibraryElement(source).getType('C').getGetter('f');
- expect(original, isNotNull);
- PropertyAccessorElement resynthesized = _validateGetElement(text, original);
- comparePropertyAccessorElements(resynthesized, original, 'C.getter f');
- }
-
- test_getElement_method() async {
- String text = 'class C { f() {} }';
- Source source = addLibrarySource('/test.dart', text);
- MethodElement original =
- context.computeLibraryElement(source).getType('C').getMethod('f');
- expect(original, isNotNull);
- MethodElement resynthesized = _validateGetElement(text, original);
- compareMethodElements(resynthesized, original, 'C.method f');
- }
-
- test_getElement_operator() async {
- String text = 'class C { operator+(x) => null; }';
- Source source = addLibrarySource('/test.dart', text);
- MethodElement original =
- context.computeLibraryElement(source).getType('C').getMethod('+');
- expect(original, isNotNull);
- MethodElement resynthesized = _validateGetElement(text, original);
- compareMethodElements(resynthesized, original, 'C.operator+');
- }
-
- test_getElement_setter() async {
- String text = 'class C { void set f(value) {} }';
- Source source = addLibrarySource('/test.dart', text);
- PropertyAccessorElement original =
- context.computeLibraryElement(source).getType('C').getSetter('f');
- expect(original, isNotNull);
- PropertyAccessorElement resynthesized = _validateGetElement(text, original);
- comparePropertyAccessorElements(resynthesized, original, 'C.setter f');
- }
-
- test_getElement_unit() async {
- String text = 'class C { f() {} }';
- Source source = addLibrarySource('/test.dart', text);
- CompilationUnitElement original =
- context.computeLibraryElement(source).definingCompilationUnit;
- expect(original, isNotNull);
- CompilationUnitElement resynthesized = _validateGetElement(text, original);
- compareCompilationUnitElements(resynthesized, original);
- }
-
- /**
- * Encode the library containing [original] into a summary and then use
- * [TestSummaryResynthesizer.getElement] to retrieve just the original
- * element from the resynthesized summary.
- */
- Element _validateGetElement(String text, Element original) {
- SummaryResynthesizer resynthesizer = encodeLibrary(original.library.source);
- ElementLocationImpl location = original.location;
- Element result = resynthesizer.getElement(location);
- checkMinimalResynthesisWork(resynthesizer, original.library);
- // Check that no other summaries needed to be resynthesized to resynthesize
- // the library element.
- expect(resynthesizer.resynthesisCount, 3);
- expect(result.location, location);
- return result;
- }
-}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 3199bbd..ab472d5 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -34,6 +34,7 @@
import '../abstract_single_unit.dart';
import '../context/abstract_context.dart';
import 'element_text.dart';
+import 'test_strategies.dart';
/**
* Abstract base class for resynthesizing and comparing elements.
@@ -44,28 +45,11 @@
Set<Source> otherLibrarySources = new Set<Source>();
/**
- * Names of variables which have initializers that are not valid constants,
- * so they are not resynthesized.
- */
- Set<String> variablesWithNotConstInitializers = new Set<String>();
-
- /**
- * Names that cannot be resolved, e.g. because of duplicate declaration.
- */
- Set<String> namesThatCannotBeResolved = new Set<String>();
-
- /**
* Tests may set this to `true` to indicate that a missing file at the time of
* summary resynthesis shouldn't trigger an error.
*/
bool allowMissingFiles = false;
- /**
- * Tests may set this to `false` to indicate that resynthesized elements
- * should not be compare with elements created using AnalysisContext.
- */
- bool shouldCompareLibraryElements = true;
-
void addLibrary(String uri) {
otherLibrarySources.add(context.sourceFactory.forUri(uri));
}
@@ -96,67 +80,6 @@
}
/**
- * Verify that the given prefix is safe to elide from a resynthesized AST.
- */
- void checkElidablePrefix(SimpleIdentifier prefix) {
- if (prefix.staticElement is! PrefixElement &&
- prefix.staticElement is! ClassElement) {
- fail('Prefix of type ${prefix.staticElement.runtimeType}'
- ' should not have been elided');
- }
- }
-
- void checkLibraryElements(
- LibraryElementImpl original, LibraryElementImpl resynthesized) {
- compareElements(resynthesized, original, '(library)');
- expect(resynthesized.displayName, original.displayName);
- expect(original.enclosingElement, isNull);
- expect(resynthesized.enclosingElement, isNull);
- expect(resynthesized.hasExtUri, original.hasExtUri);
- compareCompilationUnitElements(resynthesized.definingCompilationUnit,
- original.definingCompilationUnit);
- expect(resynthesized.parts.length, original.parts.length, reason: 'parts');
- for (int i = 0; i < resynthesized.parts.length; i++) {
- compareCompilationUnitElements(resynthesized.parts[i], original.parts[i]);
- }
- expect(resynthesized.imports.length, original.imports.length,
- reason: 'imports');
- for (int i = 0; i < resynthesized.imports.length; i++) {
- ImportElement originalImport = original.imports[i];
- compareImportElements(
- resynthesized.imports[i], originalImport, originalImport.toString());
- }
- expect(resynthesized.exports.length, original.exports.length,
- reason: 'exports');
- for (int i = 0; i < resynthesized.exports.length; i++) {
- ExportElement originalExport = original.exports[i];
- compareExportElements(
- resynthesized.exports[i], originalExport, originalExport.toString());
- }
- expect(resynthesized.nameLength, original.nameLength);
- compareNamespaces(resynthesized.publicNamespace, original.publicNamespace,
- '(public namespace)');
- compareNamespaces(resynthesized.exportNamespace, original.exportNamespace,
- '(export namespace)');
- if (original.entryPoint == null) {
- expect(resynthesized.entryPoint, isNull);
- } else {
- expect(resynthesized.entryPoint, isNotNull);
- compareFunctionElements(
- resynthesized.entryPoint, original.entryPoint, '(entry point)');
- }
- // The libraries `dart:core` and `dart:async` cannot create their
- // `loadLibrary` functions until after both are created.
- if (original.name != 'dart.core' && original.name != 'dart.async') {
- compareExecutableElements(
- resynthesized.loadLibraryFunction as ExecutableElementImpl,
- original.loadLibraryFunction as ExecutableElementImpl,
- '(loadLibraryFunction)');
- }
- expect(resynthesized.libraryCycle.toSet(), original.libraryCycle.toSet());
- }
-
- /**
* Verify that the [resynthesizer] didn't do any unnecessary work when
* resynthesizing [library].
*/
@@ -179,1008 +102,6 @@
}
}
- void checkPossibleLocalElements(Element resynthesized, Element original) {
- if (original is! LocalElement && resynthesized is! LocalElement) {
- return;
- }
- if (original is LocalElement && resynthesized is LocalElement) {
- expect(resynthesized.visibleRange, original.visibleRange);
- } else {
- fail('Incompatible local elements '
- '${resynthesized.runtimeType} vs. ${original.runtimeType}');
- }
- }
-
- void checkPossibleMember(
- Element resynthesized, Element original, String desc) {
- Element resynthesizedNonHandle = resynthesized is ElementHandle
- ? resynthesized.actualElement
- : resynthesized;
- if (original is Member) {
- expect(resynthesizedNonHandle, new TypeMatcher<Member>(), reason: desc);
- if (resynthesizedNonHandle is Member) {
- List<DartType> resynthesizedTypeArguments =
- resynthesizedNonHandle.definingType.typeArguments;
- List<DartType> originalTypeArguments =
- original.definingType.typeArguments;
- expect(
- resynthesizedTypeArguments, hasLength(originalTypeArguments.length),
- reason: desc);
- for (int i = 0; i < originalTypeArguments.length; i++) {
- compareTypeImpls(resynthesizedTypeArguments[i],
- originalTypeArguments[i], '$desc type argument $i');
- }
- }
- } else {
- expect(
- resynthesizedNonHandle, isNot(new TypeMatcher<ConstructorMember>()),
- reason: desc);
- }
- }
-
- void compareClassElements(ClassElement r, ClassElement o, String desc) {
- compareElements(r, o, desc);
- expect(r.fields.length, o.fields.length, reason: '$desc fields.length');
- for (int i = 0; i < r.fields.length; i++) {
- String name = o.fields[i].name;
- compareFieldElements(r.fields[i], o.fields[i], '$desc.field $name');
- }
- compareTypes(r.supertype, o.supertype, '$desc supertype');
- expect(r.interfaces.length, o.interfaces.length,
- reason: '$desc interfaces.length');
- for (int i = 0; i < r.interfaces.length; i++) {
- compareTypes(r.interfaces[i], o.interfaces[i],
- '$desc interface ${o.interfaces[i].name}');
- }
- expect(r.mixins.length, o.mixins.length, reason: '$desc mixins.length');
- for (int i = 0; i < r.mixins.length; i++) {
- compareTypes(r.mixins[i], o.mixins[i], '$desc mixin ${o.mixins[i].name}');
- }
- expect(r.typeParameters.length, o.typeParameters.length,
- reason: '$desc typeParameters.length');
- for (int i = 0; i < r.typeParameters.length; i++) {
- compareTypeParameterElements(r.typeParameters[i], o.typeParameters[i],
- '$desc type parameter ${o.typeParameters[i].name}');
- }
- expect(r.constructors.length, o.constructors.length,
- reason: '$desc constructors.length');
- for (int i = 0; i < r.constructors.length; i++) {
- compareConstructorElements(r.constructors[i], o.constructors[i],
- '$desc constructor ${o.constructors[i].name}');
- }
- expect(r.accessors.length, o.accessors.length,
- reason: '$desc accessors.length');
- List<PropertyAccessorElement> rAccessors = _getSortedPropertyAccessors(r);
- List<PropertyAccessorElement> oAccessors = _getSortedPropertyAccessors(o);
- for (int i = 0; i < r.accessors.length; i++) {
- comparePropertyAccessorElements(
- rAccessors[i], oAccessors[i], '$desc accessor ${oAccessors[i].name}');
- }
- expect(r.methods.length, o.methods.length, reason: '$desc methods.length');
- for (int i = 0; i < r.methods.length; i++) {
- compareMethodElements(
- r.methods[i], o.methods[i], '$desc.${o.methods[i].name}');
- }
- compareTypes(r.type, o.type, desc);
- if (r is ClassElementImpl && o is ClassElementImpl) {
- expect(r.hasBeenInferred, o.hasBeenInferred, reason: desc);
- }
- }
-
- void compareCompilationUnitElements(CompilationUnitElementImpl resynthesized,
- CompilationUnitElementImpl original) {
- String desc = 'Compilation unit ${original.source.uri}';
- expect(resynthesized.source, original.source);
- expect(resynthesized.librarySource, original.librarySource);
- compareLineInfo(resynthesized.lineInfo, original.lineInfo);
-
- expect(resynthesized.types.length, original.types.length,
- reason: '$desc.types.length');
- for (int i = 0; i < resynthesized.types.length; i++) {
- compareClassElements(
- resynthesized.types[i], original.types[i], original.types[i].name);
- }
-
- // TODO(scheglov) Uncomment once the tasks based implementation is ready.
-// expect(resynthesized.mixins.length, original.mixins.length,
-// reason: '$desc.mixins.length');
-// for (int i = 0; i < resynthesized.mixins.length; i++) {
-// compareClassElements(
-// resynthesized.mixins[i], original.mixins[i], original.mixins[i].name);
-// }
-
- expect(resynthesized.topLevelVariables.length,
- original.topLevelVariables.length,
- reason: '$desc.topLevelVariables.length');
- for (int i = 0; i < resynthesized.topLevelVariables.length; i++) {
- String name = resynthesized.topLevelVariables[i].name;
- compareTopLevelVariableElements(
- resynthesized.topLevelVariables[i],
- original.topLevelVariables
- .singleWhere((TopLevelVariableElement e) => e.name == name),
- '$desc.topLevelVariables[$name]');
- }
- expect(resynthesized.functions.length, original.functions.length,
- reason: '$desc.functions.length');
- for (int i = 0; i < resynthesized.functions.length; i++) {
- compareFunctionElements(resynthesized.functions[i], original.functions[i],
- '$desc.functions[$i] /* ${original.functions[i].name} */');
- }
- expect(resynthesized.functionTypeAliases.length,
- original.functionTypeAliases.length,
- reason: '$desc.functionTypeAliases.length');
- for (int i = 0; i < resynthesized.functionTypeAliases.length; i++) {
- compareFunctionTypeAliasElements(
- resynthesized.functionTypeAliases[i],
- original.functionTypeAliases[i],
- original.functionTypeAliases[i].name);
- }
- expect(resynthesized.enums.length, original.enums.length,
- reason: '$desc.enums.length');
- for (int i = 0; i < resynthesized.enums.length; i++) {
- compareClassElements(
- resynthesized.enums[i], original.enums[i], original.enums[i].name);
- }
- expect(resynthesized.accessors.length, original.accessors.length,
- reason: '$desc.accessors.length');
- for (int i = 0; i < resynthesized.accessors.length; i++) {
- String name = resynthesized.accessors[i].name;
- if (original.accessors[i].isGetter) {
- comparePropertyAccessorElements(
- resynthesized.accessors[i],
- original.accessors
- .singleWhere((PropertyAccessorElement e) => e.name == name),
- '$desc.accessors[$i] /* getter $name */');
- } else {
- comparePropertyAccessorElements(
- resynthesized.accessors[i],
- original.accessors
- .singleWhere((PropertyAccessorElement e) => e.name == name),
- '$desc.accessors[$i] /* setter $name */');
- }
- }
- // Note: no need to test CompilationUnitElementImpl._offsetToElementMap
- // since it is built on demand when needed (see
- // CompilationUnitElementImpl.getElementAt])
- }
-
- void compareConstAstLists(
- List<Object> rItems, List<Object> oItems, String desc) {
- if (rItems == null && oItems == null) {
- return;
- }
- expect(rItems != null && oItems != null, isTrue);
- expect(rItems, hasLength(oItems.length));
- for (int i = 0; i < oItems.length; i++) {
- Object rItem = rItems[i];
- Object oItem = oItems[i];
- if (rItem is Expression && oItem is Expression) {
- compareConstAsts(rItem, oItem, desc);
- } else if (rItem is TypeName && oItem is TypeName) {
- compareConstAsts(rItem.name, oItem.name, desc);
- } else if (rItem is InterpolationString && oItem is InterpolationString) {
- expect(rItem.value, oItem.value);
- } else if (rItem is InterpolationExpression &&
- oItem is InterpolationExpression) {
- compareConstAsts(rItem.expression, oItem.expression, desc);
- } else if (rItem is MapLiteralEntry && oItem is MapLiteralEntry) {
- compareConstAsts(rItem.key, oItem.key, desc);
- compareConstAsts(rItem.value, oItem.value, desc);
- } else if (oItem is ConstructorFieldInitializer &&
- rItem is ConstructorFieldInitializer) {
- compareConstAsts(rItem.fieldName, oItem.fieldName, desc);
- if (variablesWithNotConstInitializers.contains(rItem.fieldName.name)) {
- expect(rItem.expression, isNull, reason: desc);
- } else {
- compareConstAsts(rItem.expression, oItem.expression, desc);
- }
- } else if (oItem is AssertInitializer && rItem is AssertInitializer) {
- compareConstAsts(rItem.condition, oItem.condition, '$desc condition');
- compareConstAsts(rItem.message, oItem.message, '$desc message');
- } else if (oItem is SuperConstructorInvocation &&
- rItem is SuperConstructorInvocation) {
- compareElements(rItem.staticElement, oItem.staticElement, desc);
- compareConstAsts(rItem.constructorName, oItem.constructorName, desc);
- compareConstAstLists(
- rItem.argumentList.arguments, oItem.argumentList.arguments, desc);
- } else if (oItem is RedirectingConstructorInvocation &&
- rItem is RedirectingConstructorInvocation) {
- compareElements(rItem.staticElement, oItem.staticElement, desc);
- compareConstAsts(rItem.constructorName, oItem.constructorName, desc);
- compareConstAstLists(
- rItem.argumentList.arguments, oItem.argumentList.arguments, desc);
- } else {
- fail('$desc Incompatible item types: '
- '${rItem.runtimeType} vs. ${oItem.runtimeType}');
- }
- }
- }
-
- void compareConstAsts(AstNode r, AstNode o, String desc) {
- if (o == null) {
- expect(r, isNull, reason: desc);
- } else {
- expect(r, isNotNull, reason: desc);
- // ConstantAstCloner does not copy static types, and constant values
- // computer does not use static types. So, we don't set them during
- // resynthesis and should not check them here.
- if (o is ParenthesizedExpression) {
- // We don't resynthesize parenthesis, so just ignore it.
- compareConstAsts(r, o.expression, desc);
- } else if (o is SimpleIdentifier && r is SimpleIdentifier) {
- expect(r.name, o.name, reason: desc);
- if (namesThatCannotBeResolved.contains(r.name)) {
- expect(r.staticElement, isNull);
- } else {
- compareElements(r.staticElement, o.staticElement, desc);
- }
- } else if (o is PrefixedIdentifier && r is SimpleIdentifier) {
- // We don't resynthesize prefixed identifiers when the prefix refers to
- // a PrefixElement or a ClassElement. We use simple identifiers with
- // correct elements.
- if (o.prefix.staticElement is PrefixElement ||
- o.prefix.staticElement is ClassElement) {
- compareConstAsts(r, o.identifier, desc);
- } else {
- fail('Prefix of type ${o.prefix.staticElement.runtimeType} should not'
- ' have been elided');
- }
- } else if (o is SimpleIdentifier && r is PrefixedIdentifier) {
- // In 'class C {static const a = 0; static const b = a;}' the reference
- // to 'a' in 'b' is serialized as a fully qualified 'C.a' reference.
- if (r.prefix.staticElement is ClassElement) {
- Element oElement = resolutionMap.staticElementForIdentifier(o);
- compareElements(
- r.prefix.staticElement, oElement?.enclosingElement, desc);
- compareConstAsts(r.identifier, o, desc);
- } else {
- fail('Prefix of type ${r.prefix.staticElement.runtimeType} should not'
- ' have been elided');
- }
- } else if (o is PropertyAccess &&
- o.target is PrefixedIdentifier &&
- r is PrefixedIdentifier) {
- // We don't resynthesize prefixed identifiers when the prefix refers to
- // a PrefixElement or a ClassElement. Which means that if the original
- // expression was e.g. `prefix.topLevelVariableName.length`, it will get
- // resynthesized as `topLevelVariableName.length`
- PrefixedIdentifier oTarget = o.target;
- checkElidablePrefix(oTarget.prefix);
- compareConstAsts(
- r,
- AstTestFactory.identifier(oTarget.identifier, o.propertyName),
- desc);
- } else if (o is PrefixedIdentifier && r is PrefixedIdentifier) {
- compareConstAsts(r.prefix, o.prefix, desc);
- compareConstAsts(r.identifier, o.identifier, desc);
- } else if (o is PropertyAccess && r is PropertyAccess) {
- compareConstAsts(r.target, o.target, desc);
- String oName = o.propertyName.name;
- String rName = r.propertyName.name;
- expect(rName, oName, reason: desc);
- if (oName == 'length') {
- compareElements(
- r.propertyName.staticElement, o.propertyName.staticElement, desc);
- }
- } else if (o is PropertyAccess &&
- o.target is PrefixedIdentifier &&
- r is SimpleIdentifier) {
- // We don't resynthesize property access when it takes the form
- // `prefixName.className.staticMember`. We just resynthesize a
- // SimpleIdentifier correctly resolved to the static member.
- PrefixedIdentifier oTarget = o.target;
- checkElidablePrefix(oTarget.prefix);
- checkElidablePrefix(oTarget.identifier);
- compareConstAsts(r, o.propertyName, desc);
- } else if (o is SuperExpression && r is SuperExpression) {
- // Nothing to compare.
- } else if (o is ThisExpression && r is ThisExpression) {
- // Nothing to compare.
- } else if (o is NullLiteral) {
- expect(r, new TypeMatcher<NullLiteral>(), reason: desc);
- } else if (o is BooleanLiteral && r is BooleanLiteral) {
- expect(r.value, o.value, reason: desc);
- } else if (o is IntegerLiteral && r is IntegerLiteral) {
- expect(r.value ?? 0, o.value ?? 0, reason: desc);
- } else if (o is IntegerLiteral && r is PrefixExpression) {
- expect(r.operator.type, TokenType.MINUS);
- IntegerLiteral ri = r.operand;
- expect(-ri.value, o.value, reason: desc);
- } else if (o is DoubleLiteral && r is DoubleLiteral) {
- if (r.value != null &&
- r.value.isNaN &&
- o.value != null &&
- o.value.isNaN) {
- // NaN is not comparable.
- } else {
- expect(r.value, o.value, reason: desc);
- }
- } else if (o is StringInterpolation && r is StringInterpolation) {
- compareConstAstLists(r.elements, o.elements, desc);
- } else if (o is StringLiteral && r is StringLiteral) {
- // We don't keep all the tokens of AdjacentStrings.
- // So, we can compare only their values.
- expect(r.stringValue, o.stringValue, reason: desc);
- } else if (o is SymbolLiteral && r is SymbolLiteral) {
- // We don't keep all the tokens of symbol literals.
- // So, we can compare only their values.
- expect(r.components.map((t) => t.lexeme).join('.'),
- o.components.map((t) => t.lexeme).join('.'),
- reason: desc);
- } else if (o is NamedExpression && r is NamedExpression) {
- expect(r.name.label.name, o.name.label.name, reason: desc);
- compareConstAsts(r.expression, o.expression, desc);
- } else if (o is BinaryExpression && r is BinaryExpression) {
- expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
- compareConstAsts(r.leftOperand, o.leftOperand, desc);
- compareConstAsts(r.rightOperand, o.rightOperand, desc);
- } else if (o is PrefixExpression && r is PrefixExpression) {
- expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
- compareConstAsts(r.operand, o.operand, desc);
- } else if (o is ConditionalExpression && r is ConditionalExpression) {
- compareConstAsts(r.condition, o.condition, desc);
- compareConstAsts(r.thenExpression, o.thenExpression, desc);
- compareConstAsts(r.elseExpression, o.elseExpression, desc);
- } else if (o is ListLiteral && r is ListLiteral) {
- compareConstAstLists(
- r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
- compareConstAstLists(r.elements, o.elements, desc);
- } else if (o is MapLiteral && r is MapLiteral) {
- compareConstAstLists(
- r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
- compareConstAstLists(r.entries, o.entries, desc);
- } else if (o is MethodInvocation && r is MethodInvocation) {
- compareConstAsts(r.target, o.target, desc);
- compareConstAsts(r.methodName, o.methodName, desc);
- compareConstAstLists(
- r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
- compareConstAstLists(
- r.argumentList?.arguments, o.argumentList?.arguments, desc);
- } else if (o is InstanceCreationExpression &&
- r is InstanceCreationExpression) {
- compareElements(r.staticElement, o.staticElement, desc);
- ConstructorName oConstructor = o.constructorName;
- ConstructorName rConstructor = r.constructorName;
- expect(oConstructor, isNotNull, reason: desc);
- expect(rConstructor, isNotNull, reason: desc);
- // Note: just compare rConstructor.staticElement and
- // oConstructor.staticElement as elements, because we just want to
- // check that they're pointing to the correct elements; we don't want
- // to check that their constructor initializers match, because that
- // could lead to infinite regress.
- compareElements(
- rConstructor.staticElement, oConstructor.staticElement, desc);
- TypeName oType = oConstructor.type;
- TypeName rType = rConstructor.type;
- expect(oType, isNotNull, reason: desc);
- expect(rType, isNotNull, reason: desc);
- compareConstAsts(rType.name, oType.name, desc);
- compareConstAsts(rConstructor.name, oConstructor.name, desc);
- // In strong mode type inference is performed, so that
- // `C<int> v = new C();` is serialized as `C<int> v = new C<int>();`.
- // So, if there are not type arguments originally, not need to check.
- if (oType.typeArguments?.arguments?.isNotEmpty ?? false) {
- compareConstAstLists(rType.typeArguments?.arguments,
- oType.typeArguments?.arguments, desc);
- }
- compareConstAstLists(
- r.argumentList.arguments, o.argumentList.arguments, desc);
- } else if (o is AnnotationImpl && r is AnnotationImpl) {
- expect(o.atSign.lexeme, r.atSign.lexeme, reason: desc);
- Identifier rName = r.name;
- Identifier oName = o.name;
- if (oName is PrefixedIdentifier &&
- rName is PrefixedIdentifier &&
- o.constructorName != null &&
- o.element != null &&
- r.constructorName == null) {
- // E.g. `@prefix.cls.ctor`. This sometimes gets resynthesized as
- // `@cls.ctor`, with `cls.ctor` represented as a PrefixedIdentifier.
- compareConstAsts(rName.prefix, oName.identifier, desc);
- expect(rName.period.lexeme, '.', reason: desc);
- compareConstAsts(rName.identifier, o.constructorName, desc);
- expect(r.period, isNull, reason: desc);
- expect(r.constructorName, isNull, reason: desc);
- } else {
- compareConstAsts(r.name, o.name, desc);
- expect(r.period?.lexeme, o.period?.lexeme, reason: desc);
- compareConstAsts(r.constructorName, o.constructorName, desc);
- }
- compareConstAstLists(
- r.arguments?.arguments, o.arguments?.arguments, desc);
- compareElements(r.element, o.element, desc);
- // elementAnnotation should be null; it is only used in the full AST.
- expect(o.elementAnnotation, isNull);
- expect(r.elementAnnotation, isNull);
- } else {
- fail('Not implemented for ${r.runtimeType} vs. ${o.runtimeType}');
- }
- }
- }
-
- void compareConstructorElements(ConstructorElement resynthesized,
- ConstructorElement original, String desc) {
- if (original == null && resynthesized == null) {
- return;
- }
- compareExecutableElements(resynthesized, original, desc);
- ConstructorElementImpl resynthesizedImpl =
- getActualElement(resynthesized, desc);
- ConstructorElementImpl originalImpl = getActualElement(original, desc);
- if (original.isConst) {
- compareConstAstLists(resynthesizedImpl.constantInitializers,
- originalImpl.constantInitializers, desc);
- }
- if (original.redirectedConstructor == null) {
- expect(resynthesized.redirectedConstructor, isNull, reason: desc);
- } else {
- compareConstructorElements(resynthesized.redirectedConstructor,
- original.redirectedConstructor, '$desc redirectedConstructor');
- }
- checkPossibleMember(resynthesized, original, desc);
- expect(resynthesized.nameEnd, original.nameEnd, reason: desc);
- expect(resynthesized.periodOffset, original.periodOffset, reason: desc);
- expect(resynthesizedImpl.isCycleFree, originalImpl.isCycleFree,
- reason: desc);
- }
-
- void compareConstValues(
- DartObject resynthesized, DartObject original, String desc) {
- if (original == null) {
- expect(resynthesized, isNull, reason: desc);
- } else {
- expect(resynthesized, isNotNull, reason: desc);
- compareTypes(resynthesized.type, original.type, desc);
- expect(resynthesized.hasKnownValue, original.hasKnownValue, reason: desc);
- if (original.isNull) {
- expect(resynthesized.isNull, isTrue, reason: desc);
- } else if (original.toBoolValue() != null) {
- expect(resynthesized.toBoolValue(), original.toBoolValue(),
- reason: desc);
- } else if (original.toIntValue() != null) {
- expect(resynthesized.toIntValue(), original.toIntValue(), reason: desc);
- } else if (original.toDoubleValue() != null) {
- expect(resynthesized.toDoubleValue(), original.toDoubleValue(),
- reason: desc);
- } else if (original.toListValue() != null) {
- List<DartObject> resynthesizedList = resynthesized.toListValue();
- List<DartObject> originalList = original.toListValue();
- expect(resynthesizedList, hasLength(originalList.length));
- for (int i = 0; i < originalList.length; i++) {
- compareConstValues(resynthesizedList[i], originalList[i], desc);
- }
- } else if (original.toMapValue() != null) {
- Map<DartObject, DartObject> resynthesizedMap =
- resynthesized.toMapValue();
- Map<DartObject, DartObject> originalMap = original.toMapValue();
- expect(resynthesizedMap, hasLength(originalMap.length));
- List<DartObject> resynthesizedKeys = resynthesizedMap.keys.toList();
- List<DartObject> originalKeys = originalMap.keys.toList();
- for (int i = 0; i < originalKeys.length; i++) {
- DartObject resynthesizedKey = resynthesizedKeys[i];
- DartObject originalKey = originalKeys[i];
- compareConstValues(resynthesizedKey, originalKey, desc);
- DartObject resynthesizedValue = resynthesizedMap[resynthesizedKey];
- DartObject originalValue = originalMap[originalKey];
- compareConstValues(resynthesizedValue, originalValue, desc);
- }
- } else if (original.toStringValue() != null) {
- expect(resynthesized.toStringValue(), original.toStringValue(),
- reason: desc);
- } else if (original.toSymbolValue() != null) {
- expect(resynthesized.toSymbolValue(), original.toSymbolValue(),
- reason: desc);
- } else if (original.toTypeValue() != null) {
- fail('Not implemented');
- }
- }
- }
-
- void compareElementAnnotations(ElementAnnotationImpl resynthesized,
- ElementAnnotationImpl original, String desc) {
- if (original.element == null) {
- expect(resynthesized.element, isNull);
- } else {
- expect(resynthesized.element, isNotNull, reason: desc);
- expect(resynthesized.element.kind, original.element.kind, reason: desc);
- expect(resynthesized.element.location, original.element.location,
- reason: desc);
- }
- expect(resynthesized.compilationUnit, isNotNull, reason: desc);
- expect(resynthesized.compilationUnit.location,
- original.compilationUnit.location,
- reason: desc);
- expect(resynthesized.annotationAst, isNotNull, reason: desc);
- compareConstAsts(resynthesized.annotationAst, original.annotationAst, desc);
- }
-
- void compareElementLocations(
- Element resynthesized, Element original, String desc) {
- bool hasFunctionElementByValue(Element e) {
- if (e == null) {
- return false;
- }
- if (e is FunctionElementImpl_forLUB) {
- return true;
- }
- return hasFunctionElementByValue(e.enclosingElement);
- }
-
- if (hasFunctionElementByValue(resynthesized)) {
- // We resynthesize elements representing types of local functions
- // without corresponding name offsets, so their locations don't have
- // corresponding valid @offset components. Also, we don't put
- // resynthesized local functions into initializers of variables.
- return;
- }
- expect(resynthesized.location, original.location, reason: desc);
- }
-
- void compareElements(Element resynthesized, Element original, String desc) {
- ElementImpl rImpl = getActualElement(resynthesized, desc);
- ElementImpl oImpl = getActualElement(original, desc);
- if (oImpl == null && rImpl == null) {
- return;
- }
- if (oImpl is PrefixElement) {
- // TODO(scheglov) prefixes cannot be resynthesized
- return;
- }
- expect(original, isNotNull);
- expect(resynthesized, isNotNull, reason: desc);
- if (rImpl is DefaultParameterElementImpl && oImpl is ParameterElementImpl) {
- // This is ok provided the resynthesized parameter element doesn't have
- // any evaluation result.
- expect(rImpl.evaluationResult, isNull);
- } else {
- Type rRuntimeType;
- if (rImpl is ConstFieldElementImpl) {
- rRuntimeType = ConstFieldElementImpl;
- } else if (rImpl is FunctionElementImpl) {
- rRuntimeType = FunctionElementImpl;
- } else {
- rRuntimeType = rImpl.runtimeType;
- }
- expect(rRuntimeType, oImpl.runtimeType);
- }
- expect(resynthesized.kind, original.kind);
- compareElementLocations(resynthesized, original, desc);
- expect(resynthesized.name, original.name);
- expect(resynthesized.nameOffset, original.nameOffset,
- reason: '$desc.nameOffset');
- expect(rImpl.codeOffset, oImpl.codeOffset, reason: desc);
- expect(rImpl.codeLength, oImpl.codeLength, reason: desc);
- expect(resynthesized.documentationComment, original.documentationComment,
- reason: desc);
- compareMetadata(resynthesized.metadata, original.metadata, desc);
-
- // Validate modifiers.
- for (Modifier modifier in Modifier.values) {
- bool got = _hasModifier(resynthesized, modifier);
- bool want = _hasModifier(original, modifier);
- expect(got, want,
- reason: 'Mismatch in $desc.$modifier: got $got, want $want');
- }
-
- // Validate members.
- if (oImpl is Member) {
- expect(rImpl, new TypeMatcher<Member>(), reason: desc);
- } else {
- expect(rImpl, isNot(new TypeMatcher<Member>()), reason: desc);
- }
- }
-
- void compareExecutableElements(
- ExecutableElement resynthesized, ExecutableElement original, String desc,
- {bool shallow: false}) {
- compareElements(resynthesized, original, desc);
- compareParameterElementLists(
- resynthesized.parameters, original.parameters, desc);
- if (!original.hasImplicitReturnType) {
- compareTypes(
- resynthesized.returnType, original.returnType, '$desc return type');
- }
- if (!shallow) {
- compareTypes(resynthesized.type, original.type, desc);
- }
- expect(resynthesized.typeParameters.length, original.typeParameters.length);
- for (int i = 0; i < resynthesized.typeParameters.length; i++) {
- compareTypeParameterElements(
- resynthesized.typeParameters[i],
- original.typeParameters[i],
- '$desc type parameter ${original.typeParameters[i].name}');
- }
- }
-
- void compareExportElements(ExportElementImpl resynthesized,
- ExportElementImpl original, String desc) {
- expect(resynthesized.exportedLibrary.location,
- original.exportedLibrary.location);
- expect(resynthesized.combinators.length, original.combinators.length);
- for (int i = 0; i < resynthesized.combinators.length; i++) {
- compareNamespaceCombinators(
- resynthesized.combinators[i], original.combinators[i]);
- }
- }
-
- void compareFieldElements(
- FieldElementImpl resynthesized, FieldElementImpl original, String desc) {
- comparePropertyInducingElements(resynthesized, original, desc);
- }
-
- void compareFunctionElements(
- FunctionElement resynthesized, FunctionElement original, String desc,
- {bool shallow: false}) {
- if (original == null && resynthesized == null) {
- return;
- }
- expect(resynthesized, isNotNull, reason: desc);
- compareExecutableElements(resynthesized, original, desc, shallow: shallow);
- checkPossibleLocalElements(resynthesized, original);
- }
-
- void compareFunctionTypeAliasElements(FunctionTypeAliasElement resynthesized,
- FunctionTypeAliasElement original, String desc) {
- compareElements(resynthesized, original, desc);
- ElementImpl rImpl = getActualElement(resynthesized, desc);
- ElementImpl oImpl = getActualElement(original, desc);
- if (rImpl is GenericTypeAliasElementImpl) {
- if (oImpl is GenericTypeAliasElementImpl) {
- compareGenericFunctionTypeElements(
- rImpl.function, oImpl.function, '$desc.function');
- } else {
- fail(
- 'Resynthesized a GenericTypeAliasElementImpl, but expected a ${oImpl.runtimeType}');
- }
- } else {
- fail('Resynthesized a ${rImpl.runtimeType}');
- }
- compareTypes(resynthesized.type, original.type, desc);
- expect(resynthesized.typeParameters.length, original.typeParameters.length);
- for (int i = 0; i < resynthesized.typeParameters.length; i++) {
- compareTypeParameterElements(
- resynthesized.typeParameters[i],
- original.typeParameters[i],
- '$desc.typeParameters[$i] /* ${original.typeParameters[i].name} */');
- }
- }
-
- void compareGenericFunctionTypeElements(
- GenericFunctionTypeElement resynthesized,
- GenericFunctionTypeElement original,
- String desc) {
- if (resynthesized == null) {
- if (original != null) {
- fail('Failed to resynthesize generic function type');
- }
- } else if (original == null) {
- fail('Resynthesizes a generic function type when none expected');
- }
- compareTypeParameterElementLists(resynthesized.typeParameters,
- original.typeParameters, '$desc.typeParameters');
- compareParameterElementLists(
- resynthesized.parameters, original.parameters, '$desc.parameters');
- compareTypes(
- resynthesized.returnType, original.returnType, '$desc.returnType');
- }
-
- void compareImportElements(ImportElementImpl resynthesized,
- ImportElementImpl original, String desc) {
- expect(resynthesized.importedLibrary.location,
- original.importedLibrary.location,
- reason: '$desc importedLibrary location');
- expect(resynthesized.prefixOffset, original.prefixOffset,
- reason: '$desc prefixOffset');
- if (original.prefix == null) {
- expect(resynthesized.prefix, isNull, reason: '$desc prefix');
- } else {
- comparePrefixElements(
- resynthesized.prefix, original.prefix, original.prefix.name);
- }
- expect(resynthesized.combinators.length, original.combinators.length,
- reason: '$desc combinators');
- for (int i = 0; i < resynthesized.combinators.length; i++) {
- compareNamespaceCombinators(
- resynthesized.combinators[i], original.combinators[i]);
- }
- }
-
- void compareLabelElements(
- LabelElementImpl resynthesized, LabelElementImpl original, String desc) {
- expect(resynthesized.isOnSwitchMember, original.isOnSwitchMember,
- reason: desc);
- expect(resynthesized.isOnSwitchStatement, original.isOnSwitchStatement,
- reason: desc);
- compareElements(resynthesized, original, desc);
- }
-
- void compareLineInfo(LineInfo resynthesized, LineInfo original) {
- expect(resynthesized.lineCount, original.lineCount);
- expect(resynthesized.lineStarts, original.lineStarts);
- }
-
- void compareMetadata(List<ElementAnnotation> resynthesized,
- List<ElementAnnotation> original, String desc) {
- expect(resynthesized, hasLength(original.length), reason: desc);
- for (int i = 0; i < original.length; i++) {
- compareElementAnnotations(
- resynthesized[i], original[i], '$desc annotation $i');
- }
- }
-
- void compareMethodElements(MethodElementImpl resynthesized,
- MethodElementImpl original, String desc) {
- // TODO(paulberry): do we need to deal with
- // MultiplyInheritedMethodElementImpl?
- compareExecutableElements(resynthesized, original, desc);
- }
-
- void compareNamespaceCombinators(
- NamespaceCombinator resynthesized, NamespaceCombinator original) {
- if (original is ShowElementCombinatorImpl &&
- resynthesized is ShowElementCombinatorImpl) {
- expect(resynthesized.shownNames, original.shownNames,
- reason: 'shownNames');
- expect(resynthesized.offset, original.offset, reason: 'offset');
- expect(resynthesized.end, original.end, reason: 'end');
- } else if (original is HideElementCombinatorImpl &&
- resynthesized is HideElementCombinatorImpl) {
- expect(resynthesized.hiddenNames, original.hiddenNames,
- reason: 'hiddenNames');
- } else if (resynthesized.runtimeType != original.runtimeType) {
- fail(
- 'Type mismatch: expected ${original.runtimeType}, got ${resynthesized.runtimeType}');
- } else {
- fail('Unimplemented comparison for ${original.runtimeType}');
- }
- }
-
- void compareNamespaces(
- Namespace resynthesized, Namespace original, String desc) {
- Map<String, Element> resynthesizedMap = resynthesized.definedNames;
- Map<String, Element> originalMap = original.definedNames;
- expect(resynthesizedMap.keys.toSet(), originalMap.keys.toSet(),
- reason: desc);
- for (String key in originalMap.keys) {
- Element resynthesizedElement = resynthesizedMap[key];
- Element originalElement = originalMap[key];
- compareElements(resynthesizedElement, originalElement, key);
- }
- }
-
- void compareParameterElementLists(
- List<ParameterElement> resynthesizedParameters,
- List<ParameterElement> originalParameters,
- String desc) {
- expect(resynthesizedParameters.length, originalParameters.length);
- for (int i = 0; i < resynthesizedParameters.length; i++) {
- compareParameterElements(
- resynthesizedParameters[i],
- originalParameters[i],
- '$desc.parameters[$i] /* ${originalParameters[i].name} */');
- }
- }
-
- void compareParameterElements(
- ParameterElement resynthesized, ParameterElement original, String desc) {
- compareVariableElements(resynthesized, original, desc);
- compareParameterElementLists(
- resynthesized.parameters, original.parameters, desc);
- // ignore: deprecated_member_use
- expect(resynthesized.parameterKind, original.parameterKind, reason: desc);
- expect(resynthesized.isInitializingFormal, original.isInitializingFormal,
- reason: desc);
- expect(resynthesized is FieldFormalParameterElementImpl,
- original is FieldFormalParameterElementImpl);
- if (resynthesized is FieldFormalParameterElementImpl &&
- original is FieldFormalParameterElementImpl) {
- if (original.field == null) {
- expect(resynthesized.field, isNull, reason: '$desc field');
- } else {
- expect(resynthesized.field, isNotNull, reason: '$desc field');
- compareFieldElements(
- resynthesized.field, original.field, '$desc field');
- }
- }
- expect(resynthesized.defaultValueCode, original.defaultValueCode,
- reason: desc);
- expect(resynthesized.isCovariant, original.isCovariant,
- reason: '$desc isCovariant');
- ParameterElementImpl resynthesizedActual =
- getActualElement(resynthesized, desc);
- ParameterElementImpl originalActual = getActualElement(original, desc);
- expect(resynthesizedActual.isExplicitlyCovariant,
- originalActual.isExplicitlyCovariant,
- reason: desc);
- compareFunctionElements(
- resynthesizedActual.initializer, originalActual.initializer, desc);
- }
-
- void comparePrefixElements(PrefixElementImpl resynthesized,
- PrefixElementImpl original, String desc) {
- compareElements(resynthesized, original, desc);
- }
-
- void comparePropertyAccessorElements(
- PropertyAccessorElementImpl resynthesized,
- PropertyAccessorElementImpl original,
- String desc) {
- // TODO(paulberry): do I need to worry about
- // MultiplyInheritedPropertyAccessorElementImpl?
- compareExecutableElements(resynthesized, original, desc);
- expect(resynthesized.variable, isNotNull);
- expect(resynthesized.variable.location, original.variable.location);
- }
-
- void comparePropertyInducingElements(
- PropertyInducingElementImpl resynthesized,
- PropertyInducingElementImpl original,
- String desc) {
- compareVariableElements(resynthesized, original, desc);
- if (original.getter == null) {
- expect(resynthesized.getter, isNull);
- } else {
- expect(resynthesized.getter, isNotNull);
- expect(resynthesized.getter.location, original.getter.location);
- }
- if (original.setter == null) {
- expect(resynthesized.setter, isNull);
- } else {
- expect(resynthesized.setter, isNotNull);
- expect(resynthesized.setter.location, original.setter.location);
- }
- }
-
- void compareTopLevelVariableElements(
- TopLevelVariableElementImpl resynthesized,
- TopLevelVariableElementImpl original,
- String desc) {
- comparePropertyInducingElements(resynthesized, original, desc);
- }
-
- void compareTypeImpls(
- TypeImpl resynthesized, TypeImpl original, String desc) {
- compareElementLocations(
- resynthesized.element, original.element, '$desc.element.location');
- expect(resynthesized.name, original.name, reason: '$desc.name');
- }
-
- void compareTypeParameterElementLists(
- List<TypeParameterElement> resynthesized,
- List<TypeParameterElement> original,
- String desc) {
- int length = original.length;
- expect(resynthesized.length, length, reason: '$desc.length');
- for (int i = 0; i < length; i++) {
- compareTypeParameterElements(resynthesized[i], original[i], '$desc[$i]');
- }
- }
-
- void compareTypeParameterElements(TypeParameterElement resynthesized,
- TypeParameterElement original, String desc) {
- compareElements(resynthesized, original, desc);
- compareTypes(resynthesized.type, original.type, '$desc.type');
- compareTypes(resynthesized.bound, original.bound, '$desc.bound');
- }
-
- void compareTypes(DartType resynthesized, DartType original, String desc) {
- if (original == null) {
- expect(resynthesized, isNull, reason: desc);
- } else if (resynthesized is InterfaceTypeImpl &&
- original is InterfaceTypeImpl) {
- compareTypeImpls(resynthesized, original, desc);
- expect(resynthesized.typeArguments.length, original.typeArguments.length,
- reason: '$desc.typeArguments.length');
- for (int i = 0; i < resynthesized.typeArguments.length; i++) {
- compareTypes(resynthesized.typeArguments[i], original.typeArguments[i],
- '$desc.typeArguments[$i] /* ${original.typeArguments[i].name} */');
- }
- } else if (resynthesized is TypeParameterTypeImpl &&
- original is TypeParameterTypeImpl) {
- compareTypeImpls(resynthesized, original, desc);
- } else if (resynthesized is DynamicTypeImpl &&
- original is DynamicTypeImpl) {
- expect(resynthesized, same(original));
- } else if (resynthesized is UndefinedTypeImpl &&
- original is UndefinedTypeImpl) {
- expect(resynthesized, same(original));
- } else if (resynthesized is FunctionTypeImpl &&
- original is FunctionTypeImpl) {
- compareTypeImpls(resynthesized, original, desc);
- expect(resynthesized.isInstantiated, original.isInstantiated,
- reason: desc);
- if (original.element.enclosingElement == null &&
- original.element is FunctionElement) {
- expect(resynthesized.element, new TypeMatcher<FunctionElement>());
- expect(resynthesized.element.enclosingElement, isNull, reason: desc);
- compareFunctionElements(
- resynthesized.element, original.element, '$desc.element',
- shallow: true);
- expect(resynthesized.element.type, same(resynthesized));
- }
- expect(resynthesized.typeArguments.length, original.typeArguments.length,
- reason: '$desc.typeArguments.length');
- for (int i = 0; i < resynthesized.typeArguments.length; i++) {
- if (resynthesized.typeArguments[i].isDynamic &&
- original.typeArguments[i] is TypeParameterType) {
- // It's ok for type arguments to get converted to `dynamic` if they
- // are not used.
- expect(
- isTypeParameterUsed(
- original.typeArguments[i], original.element.type),
- isFalse);
- } else {
- compareTypes(
- resynthesized.typeArguments[i],
- original.typeArguments[i],
- '$desc.typeArguments[$i] /* ${original.typeArguments[i].name} */');
- }
- }
- if (original.typeParameters == null) {
- expect(resynthesized.typeParameters, isNull, reason: desc);
- } else {
- expect(resynthesized.typeParameters, isNotNull, reason: desc);
- expect(
- resynthesized.typeParameters.length, original.typeParameters.length,
- reason: desc);
- for (int i = 0; i < resynthesized.typeParameters.length; i++) {
- compareTypeParameterElements(resynthesized.typeParameters[i],
- original.typeParameters[i], '$desc.typeParameters[$i]');
- }
- }
- expect(resynthesized.typeFormals.length, original.typeFormals.length,
- reason: desc);
- for (int i = 0; i < resynthesized.typeFormals.length; i++) {
- compareTypeParameterElements(resynthesized.typeFormals[i],
- original.typeFormals[i], '$desc.typeFormals[$i]');
- }
- } else if (resynthesized is VoidTypeImpl && original is VoidTypeImpl) {
- expect(resynthesized, same(original));
- } else if (resynthesized is DynamicTypeImpl &&
- original is UndefinedTypeImpl) {
- // TODO(scheglov) In the strong mode constant variable like
- // `var V = new Unresolved()` gets `UndefinedTypeImpl`, and it gets
- // `DynamicTypeImpl` in the spec mode.
- } else if (resynthesized is BottomTypeImpl && original is BottomTypeImpl) {
- expect(resynthesized, same(original));
- } else if (resynthesized.runtimeType != original.runtimeType) {
- fail('Type mismatch: expected $original,'
- ' got $resynthesized ($desc)');
- } else {
- fail('Unimplemented comparison for ${original.runtimeType}');
- }
- }
-
- void compareVariableElements(
- VariableElement resynthesized, VariableElement original, String desc) {
- compareElements(resynthesized, original, desc);
- if ((resynthesized as VariableElementImpl).typeInferenceError == null) {
- compareTypes(resynthesized.type, original.type, '$desc.type');
- }
- VariableElementImpl resynthesizedActual =
- getActualElement(resynthesized, desc);
- VariableElementImpl originalActual = getActualElement(original, desc);
- compareFunctionElements(resynthesizedActual.initializer,
- originalActual.initializer, '$desc.initializer');
- if (originalActual is ConstVariableElement) {
- Element oEnclosing = original.enclosingElement;
- if (oEnclosing is ClassElement && oEnclosing.isEnum) {
- compareConstValues(resynthesized.constantValue, original.constantValue,
- '$desc.constantValue');
- } else {
- Expression initializer = resynthesizedActual.constantInitializer;
- if (variablesWithNotConstInitializers.contains(resynthesized.name)) {
- expect(initializer, isNull, reason: desc);
- } else {
- compareConstAsts(initializer, originalActual.constantInitializer,
- '$desc.constantInitializer');
- }
- }
- }
- checkPossibleMember(resynthesized, original, desc);
- checkPossibleLocalElements(resynthesized, original);
- }
-
DartSdk createDartSdk() => AbstractContextTest.SHARED_MOCK_SDK;
/**
@@ -1188,161 +109,17 @@
*/
AnalysisOptionsImpl createOptions() => new AnalysisOptionsImpl();
- ElementImpl getActualElement(Element element, String desc) {
- if (element == null) {
- return null;
- } else if (element is ElementImpl) {
- return element;
- } else if (element is ElementHandle) {
- Element actualElement = element.actualElement;
- // A handle should never point to a member, because if it did, then
- // "is Member" checks on the handle would produce the wrong result.
- expect(actualElement, isNot(new TypeMatcher<Member>()), reason: desc);
- return getActualElement(actualElement, desc);
- } else if (element is Member) {
- return getActualElement(element.baseElement, desc);
- } else {
- fail('Unexpected type for resynthesized ($desc):'
- ' ${element.runtimeType}');
- }
- }
-
- /**
- * Determine if [type] makes use of the given [typeParameter].
- */
- bool isTypeParameterUsed(TypeParameterType typeParameter, DartType type) {
- if (type is FunctionType) {
- return isTypeParameterUsed(typeParameter, type.returnType) ||
- type.parameters.any((ParameterElement e) =>
- isTypeParameterUsed(typeParameter, e.type));
- } else if (type is InterfaceType) {
- return type.typeArguments
- .any((DartType t) => isTypeParameterUsed(typeParameter, t));
- } else if (type is TypeParameterType) {
- return type == typeParameter;
- } else {
- expect(type.isDynamic || type.isVoid, isTrue);
- return false;
- }
- }
-
@override
void setUp() {
super.setUp();
prepareAnalysisContext(createOptions());
}
-
- List<PropertyAccessorElement> _getSortedPropertyAccessors(
- ClassElement classElement) {
- List<PropertyAccessorElement> accessors = classElement.accessors.toList();
- accessors.sort((a, b) => a.displayName.compareTo(b.displayName));
- return accessors;
- }
-
- bool _hasModifier(Element element, Modifier modifier) {
- if (modifier == Modifier.ABSTRACT) {
- if (element is ClassElement) {
- return element.isAbstract;
- }
- if (element is ExecutableElement) {
- return element.isAbstract;
- }
- return false;
- } else if (modifier == Modifier.ASYNCHRONOUS) {
- if (element is ExecutableElement) {
- return element.isAsynchronous;
- }
- return false;
- } else if (modifier == Modifier.CONST) {
- if (element is VariableElement) {
- return element.isConst;
- }
- return false;
- } else if (modifier == Modifier.COVARIANT) {
- if (element is ParameterElementImpl) {
- return element.isExplicitlyCovariant;
- }
- return false;
- } else if (modifier == Modifier.DEFERRED) {
- if (element is ImportElement) {
- return element.isDeferred;
- }
- return false;
- } else if (modifier == Modifier.ENUM) {
- if (element is ClassElement) {
- return element.isEnum;
- }
- return false;
- } else if (modifier == Modifier.EXTERNAL) {
- if (element is ExecutableElement) {
- return element.isExternal;
- }
- return false;
- } else if (modifier == Modifier.FACTORY) {
- if (element is ConstructorElement) {
- return element.isFactory;
- }
- return false;
- } else if (modifier == Modifier.FINAL) {
- if (element is VariableElement) {
- return element.isFinal;
- }
- return false;
- } else if (modifier == Modifier.GENERATOR) {
- if (element is ExecutableElement) {
- return element.isGenerator;
- }
- return false;
- } else if (modifier == Modifier.GETTER) {
- if (element is PropertyAccessorElement) {
- return element.isGetter;
- }
- return false;
- } else if (modifier == Modifier.HAS_EXT_URI) {
- if (element is LibraryElement) {
- return element.hasExtUri;
- }
- return false;
- } else if (modifier == Modifier.IMPLICIT_TYPE) {
- if (element is ExecutableElement) {
- return element.hasImplicitReturnType;
- }
- return false;
- } else if (modifier == Modifier.MIXIN_APPLICATION) {
- if (element is ClassElement) {
- return element.isMixinApplication;
- }
- return false;
- } else if (modifier == Modifier.REFERENCES_SUPER) {
- if (element is ClassElement) {
- return element.hasReferenceToSuper;
- }
- return false;
- } else if (modifier == Modifier.SETTER) {
- if (element is PropertyAccessorElement) {
- return element.isSetter;
- }
- return false;
- } else if (modifier == Modifier.STATIC) {
- if (element is ExecutableElement) {
- return element.isStatic;
- } else if (element is FieldElement) {
- return element.isStatic;
- }
- return false;
- } else if (modifier == Modifier.SYNTHETIC) {
- return element.isSynthetic;
- }
- throw new UnimplementedError(
- 'Modifier $modifier for ${element?.runtimeType}');
- }
}
-@reflectiveTest
-abstract class ResynthesizeTest extends AbstractResynthesizeTest {
- Future<LibraryElementImpl> checkLibrary(String text,
- {bool allowErrors: false, bool dumpSummaries: false});
-
+/// Mixin containing test cases exercising summary resynthesis. Intended to be
+/// applied to a class implementing [ResynthesizeTestStrategy], along with the
+/// mixin [ResynthesizeTestHelpers].
+abstract class ResynthesizeTestCases implements ResynthesizeTestHelpers {
test_class_abstract() async {
var library = await checkLibrary('abstract class C {}');
checkElementText(library, r'''
@@ -6106,6 +4883,88 @@
''');
}
+ test_getElement_constructor_named() async {
+ String text = 'class C { C.named(); }';
+ Source source = addLibrarySource('/test.dart', text);
+ ConstructorElement original = context
+ .computeLibraryElement(source)
+ .getType('C')
+ .getNamedConstructor('named');
+ expect(original, isNotNull);
+ ConstructorElement resynthesized = _validateGetElement(text, original);
+ compareConstructorElements(resynthesized, original, 'C.constructor named');
+ }
+
+ test_getElement_constructor_unnamed() async {
+ String text = 'class C { C(); }';
+ Source source = addLibrarySource('/test.dart', text);
+ ConstructorElement original =
+ context.computeLibraryElement(source).getType('C').unnamedConstructor;
+ expect(original, isNotNull);
+ ConstructorElement resynthesized = _validateGetElement(text, original);
+ compareConstructorElements(resynthesized, original, 'C.constructor');
+ }
+
+ test_getElement_field() async {
+ String text = 'class C { var f; }';
+ Source source = addLibrarySource('/test.dart', text);
+ FieldElement original =
+ context.computeLibraryElement(source).getType('C').getField('f');
+ expect(original, isNotNull);
+ FieldElement resynthesized = _validateGetElement(text, original);
+ compareFieldElements(resynthesized, original, 'C.field f');
+ }
+
+ test_getElement_getter() async {
+ String text = 'class C { get f => null; }';
+ Source source = addLibrarySource('/test.dart', text);
+ PropertyAccessorElement original =
+ context.computeLibraryElement(source).getType('C').getGetter('f');
+ expect(original, isNotNull);
+ PropertyAccessorElement resynthesized = _validateGetElement(text, original);
+ comparePropertyAccessorElements(resynthesized, original, 'C.getter f');
+ }
+
+ test_getElement_method() async {
+ String text = 'class C { f() {} }';
+ Source source = addLibrarySource('/test.dart', text);
+ MethodElement original =
+ context.computeLibraryElement(source).getType('C').getMethod('f');
+ expect(original, isNotNull);
+ MethodElement resynthesized = _validateGetElement(text, original);
+ compareMethodElements(resynthesized, original, 'C.method f');
+ }
+
+ test_getElement_operator() async {
+ String text = 'class C { operator+(x) => null; }';
+ Source source = addLibrarySource('/test.dart', text);
+ MethodElement original =
+ context.computeLibraryElement(source).getType('C').getMethod('+');
+ expect(original, isNotNull);
+ MethodElement resynthesized = _validateGetElement(text, original);
+ compareMethodElements(resynthesized, original, 'C.operator+');
+ }
+
+ test_getElement_setter() async {
+ String text = 'class C { void set f(value) {} }';
+ Source source = addLibrarySource('/test.dart', text);
+ PropertyAccessorElement original =
+ context.computeLibraryElement(source).getType('C').getSetter('f');
+ expect(original, isNotNull);
+ PropertyAccessorElement resynthesized = _validateGetElement(text, original);
+ comparePropertyAccessorElements(resynthesized, original, 'C.setter f');
+ }
+
+ test_getElement_unit() async {
+ String text = 'class C { f() {} }';
+ Source source = addLibrarySource('/test.dart', text);
+ CompilationUnitElement original =
+ context.computeLibraryElement(source).definingCompilationUnit;
+ expect(original, isNotNull);
+ CompilationUnitElement resynthesized = _validateGetElement(text, original);
+ compareCompilationUnitElements(resynthesized, original);
+ }
+
test_getter_documented() async {
var library = await checkLibrary('''
// Extra comment so doc comment offset != 0
@@ -9828,6 +8687,1272 @@
int j;
''');
}
+
+ /**
+ * Encode the library containing [original] into a summary and then use
+ * [TestSummaryResynthesizer.getElement] to retrieve just the original
+ * element from the resynthesized summary.
+ */
+ Element _validateGetElement(String text, Element original) {
+ SummaryResynthesizer resynthesizer = encodeLibrary(original.library.source);
+ ElementLocationImpl location = original.location;
+ Element result = resynthesizer.getElement(location);
+ checkMinimalResynthesisWork(resynthesizer, original.library);
+ // Check that no other summaries needed to be resynthesized to resynthesize
+ // the library element.
+ expect(resynthesizer.resynthesisCount, 3);
+ expect(result.location, location);
+ return result;
+ }
+}
+
+/// Mixin containing helper methods for testing summary resynthesis. Intended
+/// to be applied to a class implementing [ResynthesizeTestStrategy].
+abstract class ResynthesizeTestHelpers implements ResynthesizeTestStrategy {
+ /**
+ * Names of variables which have initializers that are not valid constants,
+ * so they are not resynthesized.
+ */
+ final variablesWithNotConstInitializers = Set<String>();
+
+ /**
+ * Tests may set this to `false` to indicate that resynthesized elements
+ * should not be compare with elements created using AnalysisContext.
+ */
+ bool shouldCompareLibraryElements = true;
+
+ /**
+ * Names that cannot be resolved, e.g. because of duplicate declaration.
+ */
+ final namesThatCannotBeResolved = Set<String>();
+
+ /**
+ * Verify that the given prefix is safe to elide from a resynthesized AST.
+ */
+ void checkElidablePrefix(SimpleIdentifier prefix) {
+ if (prefix.staticElement is! PrefixElement &&
+ prefix.staticElement is! ClassElement) {
+ fail('Prefix of type ${prefix.staticElement.runtimeType}'
+ ' should not have been elided');
+ }
+ }
+
+ Future<LibraryElementImpl> checkLibrary(String text,
+ {bool allowErrors: false, bool dumpSummaries: false}) async {
+ Source source = addTestSource(text);
+ LibraryElementImpl resynthesized = _encodeDecodeLibraryElement(source);
+ LibraryElementImpl original = context.computeLibraryElement(source);
+ if (!allowErrors) {
+ List<AnalysisError> errors = context.computeErrors(source);
+ if (errors.where((e) => e.message.startsWith('unused')).isNotEmpty) {
+ fail('Analysis errors: $errors');
+ }
+ }
+ if (shouldCompareLibraryElements) {
+ checkLibraryElements(original, resynthesized);
+ }
+ return resynthesized;
+ }
+
+ void checkLibraryElements(
+ LibraryElementImpl original, LibraryElementImpl resynthesized) {
+ compareElements(resynthesized, original, '(library)');
+ expect(resynthesized.displayName, original.displayName);
+ expect(original.enclosingElement, isNull);
+ expect(resynthesized.enclosingElement, isNull);
+ expect(resynthesized.hasExtUri, original.hasExtUri);
+ compareCompilationUnitElements(resynthesized.definingCompilationUnit,
+ original.definingCompilationUnit);
+ expect(resynthesized.parts.length, original.parts.length, reason: 'parts');
+ for (int i = 0; i < resynthesized.parts.length; i++) {
+ compareCompilationUnitElements(resynthesized.parts[i], original.parts[i]);
+ }
+ expect(resynthesized.imports.length, original.imports.length,
+ reason: 'imports');
+ for (int i = 0; i < resynthesized.imports.length; i++) {
+ ImportElement originalImport = original.imports[i];
+ compareImportElements(
+ resynthesized.imports[i], originalImport, originalImport.toString());
+ }
+ expect(resynthesized.exports.length, original.exports.length,
+ reason: 'exports');
+ for (int i = 0; i < resynthesized.exports.length; i++) {
+ ExportElement originalExport = original.exports[i];
+ compareExportElements(
+ resynthesized.exports[i], originalExport, originalExport.toString());
+ }
+ expect(resynthesized.nameLength, original.nameLength);
+ compareNamespaces(resynthesized.publicNamespace, original.publicNamespace,
+ '(public namespace)');
+ compareNamespaces(resynthesized.exportNamespace, original.exportNamespace,
+ '(export namespace)');
+ if (original.entryPoint == null) {
+ expect(resynthesized.entryPoint, isNull);
+ } else {
+ expect(resynthesized.entryPoint, isNotNull);
+ compareFunctionElements(
+ resynthesized.entryPoint, original.entryPoint, '(entry point)');
+ }
+ // The libraries `dart:core` and `dart:async` cannot create their
+ // `loadLibrary` functions until after both are created.
+ if (original.name != 'dart.core' && original.name != 'dart.async') {
+ compareExecutableElements(
+ resynthesized.loadLibraryFunction as ExecutableElementImpl,
+ original.loadLibraryFunction as ExecutableElementImpl,
+ '(loadLibraryFunction)');
+ }
+ expect(resynthesized.libraryCycle.toSet(), original.libraryCycle.toSet());
+ }
+
+ void checkPossibleLocalElements(Element resynthesized, Element original) {
+ if (original is! LocalElement && resynthesized is! LocalElement) {
+ return;
+ }
+ if (original is LocalElement && resynthesized is LocalElement) {
+ expect(resynthesized.visibleRange, original.visibleRange);
+ } else {
+ fail('Incompatible local elements '
+ '${resynthesized.runtimeType} vs. ${original.runtimeType}');
+ }
+ }
+
+ void checkPossibleMember(
+ Element resynthesized, Element original, String desc) {
+ Element resynthesizedNonHandle = resynthesized is ElementHandle
+ ? resynthesized.actualElement
+ : resynthesized;
+ if (original is Member) {
+ expect(resynthesizedNonHandle, new TypeMatcher<Member>(), reason: desc);
+ if (resynthesizedNonHandle is Member) {
+ List<DartType> resynthesizedTypeArguments =
+ resynthesizedNonHandle.definingType.typeArguments;
+ List<DartType> originalTypeArguments =
+ original.definingType.typeArguments;
+ expect(
+ resynthesizedTypeArguments, hasLength(originalTypeArguments.length),
+ reason: desc);
+ for (int i = 0; i < originalTypeArguments.length; i++) {
+ compareTypeImpls(resynthesizedTypeArguments[i],
+ originalTypeArguments[i], '$desc type argument $i');
+ }
+ }
+ } else {
+ expect(
+ resynthesizedNonHandle, isNot(new TypeMatcher<ConstructorMember>()),
+ reason: desc);
+ }
+ }
+
+ void compareClassElements(ClassElement r, ClassElement o, String desc) {
+ compareElements(r, o, desc);
+ expect(r.fields.length, o.fields.length, reason: '$desc fields.length');
+ for (int i = 0; i < r.fields.length; i++) {
+ String name = o.fields[i].name;
+ compareFieldElements(r.fields[i], o.fields[i], '$desc.field $name');
+ }
+ compareTypes(r.supertype, o.supertype, '$desc supertype');
+ expect(r.interfaces.length, o.interfaces.length,
+ reason: '$desc interfaces.length');
+ for (int i = 0; i < r.interfaces.length; i++) {
+ compareTypes(r.interfaces[i], o.interfaces[i],
+ '$desc interface ${o.interfaces[i].name}');
+ }
+ expect(r.mixins.length, o.mixins.length, reason: '$desc mixins.length');
+ for (int i = 0; i < r.mixins.length; i++) {
+ compareTypes(r.mixins[i], o.mixins[i], '$desc mixin ${o.mixins[i].name}');
+ }
+ expect(r.typeParameters.length, o.typeParameters.length,
+ reason: '$desc typeParameters.length');
+ for (int i = 0; i < r.typeParameters.length; i++) {
+ compareTypeParameterElements(r.typeParameters[i], o.typeParameters[i],
+ '$desc type parameter ${o.typeParameters[i].name}');
+ }
+ expect(r.constructors.length, o.constructors.length,
+ reason: '$desc constructors.length');
+ for (int i = 0; i < r.constructors.length; i++) {
+ compareConstructorElements(r.constructors[i], o.constructors[i],
+ '$desc constructor ${o.constructors[i].name}');
+ }
+ expect(r.accessors.length, o.accessors.length,
+ reason: '$desc accessors.length');
+ List<PropertyAccessorElement> rAccessors = _getSortedPropertyAccessors(r);
+ List<PropertyAccessorElement> oAccessors = _getSortedPropertyAccessors(o);
+ for (int i = 0; i < r.accessors.length; i++) {
+ comparePropertyAccessorElements(
+ rAccessors[i], oAccessors[i], '$desc accessor ${oAccessors[i].name}');
+ }
+ expect(r.methods.length, o.methods.length, reason: '$desc methods.length');
+ for (int i = 0; i < r.methods.length; i++) {
+ compareMethodElements(
+ r.methods[i], o.methods[i], '$desc.${o.methods[i].name}');
+ }
+ compareTypes(r.type, o.type, desc);
+ if (r is ClassElementImpl && o is ClassElementImpl) {
+ expect(r.hasBeenInferred, o.hasBeenInferred, reason: desc);
+ }
+ }
+
+ void compareCompilationUnitElements(CompilationUnitElementImpl resynthesized,
+ CompilationUnitElementImpl original) {
+ String desc = 'Compilation unit ${original.source.uri}';
+ expect(resynthesized.source, original.source);
+ expect(resynthesized.librarySource, original.librarySource);
+ compareLineInfo(resynthesized.lineInfo, original.lineInfo);
+
+ expect(resynthesized.types.length, original.types.length,
+ reason: '$desc.types.length');
+ for (int i = 0; i < resynthesized.types.length; i++) {
+ compareClassElements(
+ resynthesized.types[i], original.types[i], original.types[i].name);
+ }
+
+ // TODO(scheglov) Uncomment once the tasks based implementation is ready.
+// expect(resynthesized.mixins.length, original.mixins.length,
+// reason: '$desc.mixins.length');
+// for (int i = 0; i < resynthesized.mixins.length; i++) {
+// compareClassElements(
+// resynthesized.mixins[i], original.mixins[i], original.mixins[i].name);
+// }
+
+ expect(resynthesized.topLevelVariables.length,
+ original.topLevelVariables.length,
+ reason: '$desc.topLevelVariables.length');
+ for (int i = 0; i < resynthesized.topLevelVariables.length; i++) {
+ String name = resynthesized.topLevelVariables[i].name;
+ compareTopLevelVariableElements(
+ resynthesized.topLevelVariables[i],
+ original.topLevelVariables
+ .singleWhere((TopLevelVariableElement e) => e.name == name),
+ '$desc.topLevelVariables[$name]');
+ }
+ expect(resynthesized.functions.length, original.functions.length,
+ reason: '$desc.functions.length');
+ for (int i = 0; i < resynthesized.functions.length; i++) {
+ compareFunctionElements(resynthesized.functions[i], original.functions[i],
+ '$desc.functions[$i] /* ${original.functions[i].name} */');
+ }
+ expect(resynthesized.functionTypeAliases.length,
+ original.functionTypeAliases.length,
+ reason: '$desc.functionTypeAliases.length');
+ for (int i = 0; i < resynthesized.functionTypeAliases.length; i++) {
+ compareFunctionTypeAliasElements(
+ resynthesized.functionTypeAliases[i],
+ original.functionTypeAliases[i],
+ original.functionTypeAliases[i].name);
+ }
+ expect(resynthesized.enums.length, original.enums.length,
+ reason: '$desc.enums.length');
+ for (int i = 0; i < resynthesized.enums.length; i++) {
+ compareClassElements(
+ resynthesized.enums[i], original.enums[i], original.enums[i].name);
+ }
+ expect(resynthesized.accessors.length, original.accessors.length,
+ reason: '$desc.accessors.length');
+ for (int i = 0; i < resynthesized.accessors.length; i++) {
+ String name = resynthesized.accessors[i].name;
+ if (original.accessors[i].isGetter) {
+ comparePropertyAccessorElements(
+ resynthesized.accessors[i],
+ original.accessors
+ .singleWhere((PropertyAccessorElement e) => e.name == name),
+ '$desc.accessors[$i] /* getter $name */');
+ } else {
+ comparePropertyAccessorElements(
+ resynthesized.accessors[i],
+ original.accessors
+ .singleWhere((PropertyAccessorElement e) => e.name == name),
+ '$desc.accessors[$i] /* setter $name */');
+ }
+ }
+ // Note: no need to test CompilationUnitElementImpl._offsetToElementMap
+ // since it is built on demand when needed (see
+ // CompilationUnitElementImpl.getElementAt])
+ }
+
+ void compareConstAstLists(
+ List<Object> rItems, List<Object> oItems, String desc) {
+ if (rItems == null && oItems == null) {
+ return;
+ }
+ expect(rItems != null && oItems != null, isTrue);
+ expect(rItems, hasLength(oItems.length));
+ for (int i = 0; i < oItems.length; i++) {
+ Object rItem = rItems[i];
+ Object oItem = oItems[i];
+ if (rItem is Expression && oItem is Expression) {
+ compareConstAsts(rItem, oItem, desc);
+ } else if (rItem is TypeName && oItem is TypeName) {
+ compareConstAsts(rItem.name, oItem.name, desc);
+ } else if (rItem is InterpolationString && oItem is InterpolationString) {
+ expect(rItem.value, oItem.value);
+ } else if (rItem is InterpolationExpression &&
+ oItem is InterpolationExpression) {
+ compareConstAsts(rItem.expression, oItem.expression, desc);
+ } else if (rItem is MapLiteralEntry && oItem is MapLiteralEntry) {
+ compareConstAsts(rItem.key, oItem.key, desc);
+ compareConstAsts(rItem.value, oItem.value, desc);
+ } else if (oItem is ConstructorFieldInitializer &&
+ rItem is ConstructorFieldInitializer) {
+ compareConstAsts(rItem.fieldName, oItem.fieldName, desc);
+ if (variablesWithNotConstInitializers.contains(rItem.fieldName.name)) {
+ expect(rItem.expression, isNull, reason: desc);
+ } else {
+ compareConstAsts(rItem.expression, oItem.expression, desc);
+ }
+ } else if (oItem is AssertInitializer && rItem is AssertInitializer) {
+ compareConstAsts(rItem.condition, oItem.condition, '$desc condition');
+ compareConstAsts(rItem.message, oItem.message, '$desc message');
+ } else if (oItem is SuperConstructorInvocation &&
+ rItem is SuperConstructorInvocation) {
+ compareElements(rItem.staticElement, oItem.staticElement, desc);
+ compareConstAsts(rItem.constructorName, oItem.constructorName, desc);
+ compareConstAstLists(
+ rItem.argumentList.arguments, oItem.argumentList.arguments, desc);
+ } else if (oItem is RedirectingConstructorInvocation &&
+ rItem is RedirectingConstructorInvocation) {
+ compareElements(rItem.staticElement, oItem.staticElement, desc);
+ compareConstAsts(rItem.constructorName, oItem.constructorName, desc);
+ compareConstAstLists(
+ rItem.argumentList.arguments, oItem.argumentList.arguments, desc);
+ } else {
+ fail('$desc Incompatible item types: '
+ '${rItem.runtimeType} vs. ${oItem.runtimeType}');
+ }
+ }
+ }
+
+ void compareConstAsts(AstNode r, AstNode o, String desc) {
+ if (o == null) {
+ expect(r, isNull, reason: desc);
+ } else {
+ expect(r, isNotNull, reason: desc);
+ // ConstantAstCloner does not copy static types, and constant values
+ // computer does not use static types. So, we don't set them during
+ // resynthesis and should not check them here.
+ if (o is ParenthesizedExpression) {
+ // We don't resynthesize parenthesis, so just ignore it.
+ compareConstAsts(r, o.expression, desc);
+ } else if (o is SimpleIdentifier && r is SimpleIdentifier) {
+ expect(r.name, o.name, reason: desc);
+ if (namesThatCannotBeResolved.contains(r.name)) {
+ expect(r.staticElement, isNull);
+ } else {
+ compareElements(r.staticElement, o.staticElement, desc);
+ }
+ } else if (o is PrefixedIdentifier && r is SimpleIdentifier) {
+ // We don't resynthesize prefixed identifiers when the prefix refers to
+ // a PrefixElement or a ClassElement. We use simple identifiers with
+ // correct elements.
+ if (o.prefix.staticElement is PrefixElement ||
+ o.prefix.staticElement is ClassElement) {
+ compareConstAsts(r, o.identifier, desc);
+ } else {
+ fail('Prefix of type ${o.prefix.staticElement.runtimeType} should not'
+ ' have been elided');
+ }
+ } else if (o is SimpleIdentifier && r is PrefixedIdentifier) {
+ // In 'class C {static const a = 0; static const b = a;}' the reference
+ // to 'a' in 'b' is serialized as a fully qualified 'C.a' reference.
+ if (r.prefix.staticElement is ClassElement) {
+ Element oElement = resolutionMap.staticElementForIdentifier(o);
+ compareElements(
+ r.prefix.staticElement, oElement?.enclosingElement, desc);
+ compareConstAsts(r.identifier, o, desc);
+ } else {
+ fail('Prefix of type ${r.prefix.staticElement.runtimeType} should not'
+ ' have been elided');
+ }
+ } else if (o is PropertyAccess &&
+ o.target is PrefixedIdentifier &&
+ r is PrefixedIdentifier) {
+ // We don't resynthesize prefixed identifiers when the prefix refers to
+ // a PrefixElement or a ClassElement. Which means that if the original
+ // expression was e.g. `prefix.topLevelVariableName.length`, it will get
+ // resynthesized as `topLevelVariableName.length`
+ PrefixedIdentifier oTarget = o.target;
+ checkElidablePrefix(oTarget.prefix);
+ compareConstAsts(
+ r,
+ AstTestFactory.identifier(oTarget.identifier, o.propertyName),
+ desc);
+ } else if (o is PrefixedIdentifier && r is PrefixedIdentifier) {
+ compareConstAsts(r.prefix, o.prefix, desc);
+ compareConstAsts(r.identifier, o.identifier, desc);
+ } else if (o is PropertyAccess && r is PropertyAccess) {
+ compareConstAsts(r.target, o.target, desc);
+ String oName = o.propertyName.name;
+ String rName = r.propertyName.name;
+ expect(rName, oName, reason: desc);
+ if (oName == 'length') {
+ compareElements(
+ r.propertyName.staticElement, o.propertyName.staticElement, desc);
+ }
+ } else if (o is PropertyAccess &&
+ o.target is PrefixedIdentifier &&
+ r is SimpleIdentifier) {
+ // We don't resynthesize property access when it takes the form
+ // `prefixName.className.staticMember`. We just resynthesize a
+ // SimpleIdentifier correctly resolved to the static member.
+ PrefixedIdentifier oTarget = o.target;
+ checkElidablePrefix(oTarget.prefix);
+ checkElidablePrefix(oTarget.identifier);
+ compareConstAsts(r, o.propertyName, desc);
+ } else if (o is SuperExpression && r is SuperExpression) {
+ // Nothing to compare.
+ } else if (o is ThisExpression && r is ThisExpression) {
+ // Nothing to compare.
+ } else if (o is NullLiteral) {
+ expect(r, new TypeMatcher<NullLiteral>(), reason: desc);
+ } else if (o is BooleanLiteral && r is BooleanLiteral) {
+ expect(r.value, o.value, reason: desc);
+ } else if (o is IntegerLiteral && r is IntegerLiteral) {
+ expect(r.value ?? 0, o.value ?? 0, reason: desc);
+ } else if (o is IntegerLiteral && r is PrefixExpression) {
+ expect(r.operator.type, TokenType.MINUS);
+ IntegerLiteral ri = r.operand;
+ expect(-ri.value, o.value, reason: desc);
+ } else if (o is DoubleLiteral && r is DoubleLiteral) {
+ if (r.value != null &&
+ r.value.isNaN &&
+ o.value != null &&
+ o.value.isNaN) {
+ // NaN is not comparable.
+ } else {
+ expect(r.value, o.value, reason: desc);
+ }
+ } else if (o is StringInterpolation && r is StringInterpolation) {
+ compareConstAstLists(r.elements, o.elements, desc);
+ } else if (o is StringLiteral && r is StringLiteral) {
+ // We don't keep all the tokens of AdjacentStrings.
+ // So, we can compare only their values.
+ expect(r.stringValue, o.stringValue, reason: desc);
+ } else if (o is SymbolLiteral && r is SymbolLiteral) {
+ // We don't keep all the tokens of symbol literals.
+ // So, we can compare only their values.
+ expect(r.components.map((t) => t.lexeme).join('.'),
+ o.components.map((t) => t.lexeme).join('.'),
+ reason: desc);
+ } else if (o is NamedExpression && r is NamedExpression) {
+ expect(r.name.label.name, o.name.label.name, reason: desc);
+ compareConstAsts(r.expression, o.expression, desc);
+ } else if (o is BinaryExpression && r is BinaryExpression) {
+ expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
+ compareConstAsts(r.leftOperand, o.leftOperand, desc);
+ compareConstAsts(r.rightOperand, o.rightOperand, desc);
+ } else if (o is PrefixExpression && r is PrefixExpression) {
+ expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
+ compareConstAsts(r.operand, o.operand, desc);
+ } else if (o is ConditionalExpression && r is ConditionalExpression) {
+ compareConstAsts(r.condition, o.condition, desc);
+ compareConstAsts(r.thenExpression, o.thenExpression, desc);
+ compareConstAsts(r.elseExpression, o.elseExpression, desc);
+ } else if (o is ListLiteral && r is ListLiteral) {
+ compareConstAstLists(
+ r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
+ compareConstAstLists(r.elements, o.elements, desc);
+ } else if (o is MapLiteral && r is MapLiteral) {
+ compareConstAstLists(
+ r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
+ compareConstAstLists(r.entries, o.entries, desc);
+ } else if (o is MethodInvocation && r is MethodInvocation) {
+ compareConstAsts(r.target, o.target, desc);
+ compareConstAsts(r.methodName, o.methodName, desc);
+ compareConstAstLists(
+ r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
+ compareConstAstLists(
+ r.argumentList?.arguments, o.argumentList?.arguments, desc);
+ } else if (o is InstanceCreationExpression &&
+ r is InstanceCreationExpression) {
+ compareElements(r.staticElement, o.staticElement, desc);
+ ConstructorName oConstructor = o.constructorName;
+ ConstructorName rConstructor = r.constructorName;
+ expect(oConstructor, isNotNull, reason: desc);
+ expect(rConstructor, isNotNull, reason: desc);
+ // Note: just compare rConstructor.staticElement and
+ // oConstructor.staticElement as elements, because we just want to
+ // check that they're pointing to the correct elements; we don't want
+ // to check that their constructor initializers match, because that
+ // could lead to infinite regress.
+ compareElements(
+ rConstructor.staticElement, oConstructor.staticElement, desc);
+ TypeName oType = oConstructor.type;
+ TypeName rType = rConstructor.type;
+ expect(oType, isNotNull, reason: desc);
+ expect(rType, isNotNull, reason: desc);
+ compareConstAsts(rType.name, oType.name, desc);
+ compareConstAsts(rConstructor.name, oConstructor.name, desc);
+ // In strong mode type inference is performed, so that
+ // `C<int> v = new C();` is serialized as `C<int> v = new C<int>();`.
+ // So, if there are not type arguments originally, not need to check.
+ if (oType.typeArguments?.arguments?.isNotEmpty ?? false) {
+ compareConstAstLists(rType.typeArguments?.arguments,
+ oType.typeArguments?.arguments, desc);
+ }
+ compareConstAstLists(
+ r.argumentList.arguments, o.argumentList.arguments, desc);
+ } else if (o is AnnotationImpl && r is AnnotationImpl) {
+ expect(o.atSign.lexeme, r.atSign.lexeme, reason: desc);
+ Identifier rName = r.name;
+ Identifier oName = o.name;
+ if (oName is PrefixedIdentifier &&
+ rName is PrefixedIdentifier &&
+ o.constructorName != null &&
+ o.element != null &&
+ r.constructorName == null) {
+ // E.g. `@prefix.cls.ctor`. This sometimes gets resynthesized as
+ // `@cls.ctor`, with `cls.ctor` represented as a PrefixedIdentifier.
+ compareConstAsts(rName.prefix, oName.identifier, desc);
+ expect(rName.period.lexeme, '.', reason: desc);
+ compareConstAsts(rName.identifier, o.constructorName, desc);
+ expect(r.period, isNull, reason: desc);
+ expect(r.constructorName, isNull, reason: desc);
+ } else {
+ compareConstAsts(r.name, o.name, desc);
+ expect(r.period?.lexeme, o.period?.lexeme, reason: desc);
+ compareConstAsts(r.constructorName, o.constructorName, desc);
+ }
+ compareConstAstLists(
+ r.arguments?.arguments, o.arguments?.arguments, desc);
+ compareElements(r.element, o.element, desc);
+ // elementAnnotation should be null; it is only used in the full AST.
+ expect(o.elementAnnotation, isNull);
+ expect(r.elementAnnotation, isNull);
+ } else {
+ fail('Not implemented for ${r.runtimeType} vs. ${o.runtimeType}');
+ }
+ }
+ }
+
+ void compareConstructorElements(ConstructorElement resynthesized,
+ ConstructorElement original, String desc) {
+ if (original == null && resynthesized == null) {
+ return;
+ }
+ compareExecutableElements(resynthesized, original, desc);
+ ConstructorElementImpl resynthesizedImpl =
+ getActualElement(resynthesized, desc);
+ ConstructorElementImpl originalImpl = getActualElement(original, desc);
+ if (original.isConst) {
+ compareConstAstLists(resynthesizedImpl.constantInitializers,
+ originalImpl.constantInitializers, desc);
+ }
+ if (original.redirectedConstructor == null) {
+ expect(resynthesized.redirectedConstructor, isNull, reason: desc);
+ } else {
+ compareConstructorElements(resynthesized.redirectedConstructor,
+ original.redirectedConstructor, '$desc redirectedConstructor');
+ }
+ checkPossibleMember(resynthesized, original, desc);
+ expect(resynthesized.nameEnd, original.nameEnd, reason: desc);
+ expect(resynthesized.periodOffset, original.periodOffset, reason: desc);
+ expect(resynthesizedImpl.isCycleFree, originalImpl.isCycleFree,
+ reason: desc);
+ }
+
+ void compareConstValues(
+ DartObject resynthesized, DartObject original, String desc) {
+ if (original == null) {
+ expect(resynthesized, isNull, reason: desc);
+ } else {
+ expect(resynthesized, isNotNull, reason: desc);
+ compareTypes(resynthesized.type, original.type, desc);
+ expect(resynthesized.hasKnownValue, original.hasKnownValue, reason: desc);
+ if (original.isNull) {
+ expect(resynthesized.isNull, isTrue, reason: desc);
+ } else if (original.toBoolValue() != null) {
+ expect(resynthesized.toBoolValue(), original.toBoolValue(),
+ reason: desc);
+ } else if (original.toIntValue() != null) {
+ expect(resynthesized.toIntValue(), original.toIntValue(), reason: desc);
+ } else if (original.toDoubleValue() != null) {
+ expect(resynthesized.toDoubleValue(), original.toDoubleValue(),
+ reason: desc);
+ } else if (original.toListValue() != null) {
+ List<DartObject> resynthesizedList = resynthesized.toListValue();
+ List<DartObject> originalList = original.toListValue();
+ expect(resynthesizedList, hasLength(originalList.length));
+ for (int i = 0; i < originalList.length; i++) {
+ compareConstValues(resynthesizedList[i], originalList[i], desc);
+ }
+ } else if (original.toMapValue() != null) {
+ Map<DartObject, DartObject> resynthesizedMap =
+ resynthesized.toMapValue();
+ Map<DartObject, DartObject> originalMap = original.toMapValue();
+ expect(resynthesizedMap, hasLength(originalMap.length));
+ List<DartObject> resynthesizedKeys = resynthesizedMap.keys.toList();
+ List<DartObject> originalKeys = originalMap.keys.toList();
+ for (int i = 0; i < originalKeys.length; i++) {
+ DartObject resynthesizedKey = resynthesizedKeys[i];
+ DartObject originalKey = originalKeys[i];
+ compareConstValues(resynthesizedKey, originalKey, desc);
+ DartObject resynthesizedValue = resynthesizedMap[resynthesizedKey];
+ DartObject originalValue = originalMap[originalKey];
+ compareConstValues(resynthesizedValue, originalValue, desc);
+ }
+ } else if (original.toStringValue() != null) {
+ expect(resynthesized.toStringValue(), original.toStringValue(),
+ reason: desc);
+ } else if (original.toSymbolValue() != null) {
+ expect(resynthesized.toSymbolValue(), original.toSymbolValue(),
+ reason: desc);
+ } else if (original.toTypeValue() != null) {
+ fail('Not implemented');
+ }
+ }
+ }
+
+ void compareElementAnnotations(ElementAnnotationImpl resynthesized,
+ ElementAnnotationImpl original, String desc) {
+ if (original.element == null) {
+ expect(resynthesized.element, isNull);
+ } else {
+ expect(resynthesized.element, isNotNull, reason: desc);
+ expect(resynthesized.element.kind, original.element.kind, reason: desc);
+ expect(resynthesized.element.location, original.element.location,
+ reason: desc);
+ }
+ expect(resynthesized.compilationUnit, isNotNull, reason: desc);
+ expect(resynthesized.compilationUnit.location,
+ original.compilationUnit.location,
+ reason: desc);
+ expect(resynthesized.annotationAst, isNotNull, reason: desc);
+ compareConstAsts(resynthesized.annotationAst, original.annotationAst, desc);
+ }
+
+ void compareElementLocations(
+ Element resynthesized, Element original, String desc) {
+ bool hasFunctionElementByValue(Element e) {
+ if (e == null) {
+ return false;
+ }
+ if (e is FunctionElementImpl_forLUB) {
+ return true;
+ }
+ return hasFunctionElementByValue(e.enclosingElement);
+ }
+
+ if (hasFunctionElementByValue(resynthesized)) {
+ // We resynthesize elements representing types of local functions
+ // without corresponding name offsets, so their locations don't have
+ // corresponding valid @offset components. Also, we don't put
+ // resynthesized local functions into initializers of variables.
+ return;
+ }
+ expect(resynthesized.location, original.location, reason: desc);
+ }
+
+ void compareElements(Element resynthesized, Element original, String desc) {
+ ElementImpl rImpl = getActualElement(resynthesized, desc);
+ ElementImpl oImpl = getActualElement(original, desc);
+ if (oImpl == null && rImpl == null) {
+ return;
+ }
+ if (oImpl is PrefixElement) {
+ // TODO(scheglov) prefixes cannot be resynthesized
+ return;
+ }
+ expect(original, isNotNull);
+ expect(resynthesized, isNotNull, reason: desc);
+ if (rImpl is DefaultParameterElementImpl && oImpl is ParameterElementImpl) {
+ // This is ok provided the resynthesized parameter element doesn't have
+ // any evaluation result.
+ expect(rImpl.evaluationResult, isNull);
+ } else {
+ Type rRuntimeType;
+ if (rImpl is ConstFieldElementImpl) {
+ rRuntimeType = ConstFieldElementImpl;
+ } else if (rImpl is FunctionElementImpl) {
+ rRuntimeType = FunctionElementImpl;
+ } else {
+ rRuntimeType = rImpl.runtimeType;
+ }
+ expect(rRuntimeType, oImpl.runtimeType);
+ }
+ expect(resynthesized.kind, original.kind);
+ compareElementLocations(resynthesized, original, desc);
+ expect(resynthesized.name, original.name);
+ expect(resynthesized.nameOffset, original.nameOffset,
+ reason: '$desc.nameOffset');
+ expect(rImpl.codeOffset, oImpl.codeOffset, reason: desc);
+ expect(rImpl.codeLength, oImpl.codeLength, reason: desc);
+ expect(resynthesized.documentationComment, original.documentationComment,
+ reason: desc);
+ compareMetadata(resynthesized.metadata, original.metadata, desc);
+
+ // Validate modifiers.
+ for (Modifier modifier in Modifier.values) {
+ bool got = _hasModifier(resynthesized, modifier);
+ bool want = _hasModifier(original, modifier);
+ expect(got, want,
+ reason: 'Mismatch in $desc.$modifier: got $got, want $want');
+ }
+
+ // Validate members.
+ if (oImpl is Member) {
+ expect(rImpl, new TypeMatcher<Member>(), reason: desc);
+ } else {
+ expect(rImpl, isNot(new TypeMatcher<Member>()), reason: desc);
+ }
+ }
+
+ void compareExecutableElements(
+ ExecutableElement resynthesized, ExecutableElement original, String desc,
+ {bool shallow: false}) {
+ compareElements(resynthesized, original, desc);
+ compareParameterElementLists(
+ resynthesized.parameters, original.parameters, desc);
+ if (!original.hasImplicitReturnType) {
+ compareTypes(
+ resynthesized.returnType, original.returnType, '$desc return type');
+ }
+ if (!shallow) {
+ compareTypes(resynthesized.type, original.type, desc);
+ }
+ expect(resynthesized.typeParameters.length, original.typeParameters.length);
+ for (int i = 0; i < resynthesized.typeParameters.length; i++) {
+ compareTypeParameterElements(
+ resynthesized.typeParameters[i],
+ original.typeParameters[i],
+ '$desc type parameter ${original.typeParameters[i].name}');
+ }
+ }
+
+ void compareExportElements(ExportElementImpl resynthesized,
+ ExportElementImpl original, String desc) {
+ expect(resynthesized.exportedLibrary.location,
+ original.exportedLibrary.location);
+ expect(resynthesized.combinators.length, original.combinators.length);
+ for (int i = 0; i < resynthesized.combinators.length; i++) {
+ compareNamespaceCombinators(
+ resynthesized.combinators[i], original.combinators[i]);
+ }
+ }
+
+ void compareFieldElements(
+ FieldElementImpl resynthesized, FieldElementImpl original, String desc) {
+ comparePropertyInducingElements(resynthesized, original, desc);
+ }
+
+ void compareFunctionElements(
+ FunctionElement resynthesized, FunctionElement original, String desc,
+ {bool shallow: false}) {
+ if (original == null && resynthesized == null) {
+ return;
+ }
+ expect(resynthesized, isNotNull, reason: desc);
+ compareExecutableElements(resynthesized, original, desc, shallow: shallow);
+ checkPossibleLocalElements(resynthesized, original);
+ }
+
+ void compareFunctionTypeAliasElements(FunctionTypeAliasElement resynthesized,
+ FunctionTypeAliasElement original, String desc) {
+ compareElements(resynthesized, original, desc);
+ ElementImpl rImpl = getActualElement(resynthesized, desc);
+ ElementImpl oImpl = getActualElement(original, desc);
+ if (rImpl is GenericTypeAliasElementImpl) {
+ if (oImpl is GenericTypeAliasElementImpl) {
+ compareGenericFunctionTypeElements(
+ rImpl.function, oImpl.function, '$desc.function');
+ } else {
+ fail(
+ 'Resynthesized a GenericTypeAliasElementImpl, but expected a ${oImpl.runtimeType}');
+ }
+ } else {
+ fail('Resynthesized a ${rImpl.runtimeType}');
+ }
+ compareTypes(resynthesized.type, original.type, desc);
+ expect(resynthesized.typeParameters.length, original.typeParameters.length);
+ for (int i = 0; i < resynthesized.typeParameters.length; i++) {
+ compareTypeParameterElements(
+ resynthesized.typeParameters[i],
+ original.typeParameters[i],
+ '$desc.typeParameters[$i] /* ${original.typeParameters[i].name} */');
+ }
+ }
+
+ void compareGenericFunctionTypeElements(
+ GenericFunctionTypeElement resynthesized,
+ GenericFunctionTypeElement original,
+ String desc) {
+ if (resynthesized == null) {
+ if (original != null) {
+ fail('Failed to resynthesize generic function type');
+ }
+ } else if (original == null) {
+ fail('Resynthesizes a generic function type when none expected');
+ }
+ compareTypeParameterElementLists(resynthesized.typeParameters,
+ original.typeParameters, '$desc.typeParameters');
+ compareParameterElementLists(
+ resynthesized.parameters, original.parameters, '$desc.parameters');
+ compareTypes(
+ resynthesized.returnType, original.returnType, '$desc.returnType');
+ }
+
+ void compareImportElements(ImportElementImpl resynthesized,
+ ImportElementImpl original, String desc) {
+ expect(resynthesized.importedLibrary.location,
+ original.importedLibrary.location,
+ reason: '$desc importedLibrary location');
+ expect(resynthesized.prefixOffset, original.prefixOffset,
+ reason: '$desc prefixOffset');
+ if (original.prefix == null) {
+ expect(resynthesized.prefix, isNull, reason: '$desc prefix');
+ } else {
+ comparePrefixElements(
+ resynthesized.prefix, original.prefix, original.prefix.name);
+ }
+ expect(resynthesized.combinators.length, original.combinators.length,
+ reason: '$desc combinators');
+ for (int i = 0; i < resynthesized.combinators.length; i++) {
+ compareNamespaceCombinators(
+ resynthesized.combinators[i], original.combinators[i]);
+ }
+ }
+
+ void compareLabelElements(
+ LabelElementImpl resynthesized, LabelElementImpl original, String desc) {
+ expect(resynthesized.isOnSwitchMember, original.isOnSwitchMember,
+ reason: desc);
+ expect(resynthesized.isOnSwitchStatement, original.isOnSwitchStatement,
+ reason: desc);
+ compareElements(resynthesized, original, desc);
+ }
+
+ void compareLineInfo(LineInfo resynthesized, LineInfo original) {
+ expect(resynthesized.lineCount, original.lineCount);
+ expect(resynthesized.lineStarts, original.lineStarts);
+ }
+
+ void compareMetadata(List<ElementAnnotation> resynthesized,
+ List<ElementAnnotation> original, String desc) {
+ expect(resynthesized, hasLength(original.length), reason: desc);
+ for (int i = 0; i < original.length; i++) {
+ compareElementAnnotations(
+ resynthesized[i], original[i], '$desc annotation $i');
+ }
+ }
+
+ void compareMethodElements(MethodElementImpl resynthesized,
+ MethodElementImpl original, String desc) {
+ // TODO(paulberry): do we need to deal with
+ // MultiplyInheritedMethodElementImpl?
+ compareExecutableElements(resynthesized, original, desc);
+ }
+
+ void compareNamespaceCombinators(
+ NamespaceCombinator resynthesized, NamespaceCombinator original) {
+ if (original is ShowElementCombinatorImpl &&
+ resynthesized is ShowElementCombinatorImpl) {
+ expect(resynthesized.shownNames, original.shownNames,
+ reason: 'shownNames');
+ expect(resynthesized.offset, original.offset, reason: 'offset');
+ expect(resynthesized.end, original.end, reason: 'end');
+ } else if (original is HideElementCombinatorImpl &&
+ resynthesized is HideElementCombinatorImpl) {
+ expect(resynthesized.hiddenNames, original.hiddenNames,
+ reason: 'hiddenNames');
+ } else if (resynthesized.runtimeType != original.runtimeType) {
+ fail(
+ 'Type mismatch: expected ${original.runtimeType}, got ${resynthesized.runtimeType}');
+ } else {
+ fail('Unimplemented comparison for ${original.runtimeType}');
+ }
+ }
+
+ void compareNamespaces(
+ Namespace resynthesized, Namespace original, String desc) {
+ Map<String, Element> resynthesizedMap = resynthesized.definedNames;
+ Map<String, Element> originalMap = original.definedNames;
+ expect(resynthesizedMap.keys.toSet(), originalMap.keys.toSet(),
+ reason: desc);
+ for (String key in originalMap.keys) {
+ Element resynthesizedElement = resynthesizedMap[key];
+ Element originalElement = originalMap[key];
+ compareElements(resynthesizedElement, originalElement, key);
+ }
+ }
+
+ void compareParameterElementLists(
+ List<ParameterElement> resynthesizedParameters,
+ List<ParameterElement> originalParameters,
+ String desc) {
+ expect(resynthesizedParameters.length, originalParameters.length);
+ for (int i = 0; i < resynthesizedParameters.length; i++) {
+ compareParameterElements(
+ resynthesizedParameters[i],
+ originalParameters[i],
+ '$desc.parameters[$i] /* ${originalParameters[i].name} */');
+ }
+ }
+
+ void compareParameterElements(
+ ParameterElement resynthesized, ParameterElement original, String desc) {
+ compareVariableElements(resynthesized, original, desc);
+ compareParameterElementLists(
+ resynthesized.parameters, original.parameters, desc);
+ // ignore: deprecated_member_use
+ expect(resynthesized.parameterKind, original.parameterKind, reason: desc);
+ expect(resynthesized.isInitializingFormal, original.isInitializingFormal,
+ reason: desc);
+ expect(resynthesized is FieldFormalParameterElementImpl,
+ original is FieldFormalParameterElementImpl);
+ if (resynthesized is FieldFormalParameterElementImpl &&
+ original is FieldFormalParameterElementImpl) {
+ if (original.field == null) {
+ expect(resynthesized.field, isNull, reason: '$desc field');
+ } else {
+ expect(resynthesized.field, isNotNull, reason: '$desc field');
+ compareFieldElements(
+ resynthesized.field, original.field, '$desc field');
+ }
+ }
+ expect(resynthesized.defaultValueCode, original.defaultValueCode,
+ reason: desc);
+ expect(resynthesized.isCovariant, original.isCovariant,
+ reason: '$desc isCovariant');
+ ParameterElementImpl resynthesizedActual =
+ getActualElement(resynthesized, desc);
+ ParameterElementImpl originalActual = getActualElement(original, desc);
+ expect(resynthesizedActual.isExplicitlyCovariant,
+ originalActual.isExplicitlyCovariant,
+ reason: desc);
+ compareFunctionElements(
+ resynthesizedActual.initializer, originalActual.initializer, desc);
+ }
+
+ void comparePrefixElements(PrefixElementImpl resynthesized,
+ PrefixElementImpl original, String desc) {
+ compareElements(resynthesized, original, desc);
+ }
+
+ void comparePropertyAccessorElements(
+ PropertyAccessorElementImpl resynthesized,
+ PropertyAccessorElementImpl original,
+ String desc) {
+ // TODO(paulberry): do I need to worry about
+ // MultiplyInheritedPropertyAccessorElementImpl?
+ compareExecutableElements(resynthesized, original, desc);
+ expect(resynthesized.variable, isNotNull);
+ expect(resynthesized.variable.location, original.variable.location);
+ }
+
+ void comparePropertyInducingElements(
+ PropertyInducingElementImpl resynthesized,
+ PropertyInducingElementImpl original,
+ String desc) {
+ compareVariableElements(resynthesized, original, desc);
+ if (original.getter == null) {
+ expect(resynthesized.getter, isNull);
+ } else {
+ expect(resynthesized.getter, isNotNull);
+ expect(resynthesized.getter.location, original.getter.location);
+ }
+ if (original.setter == null) {
+ expect(resynthesized.setter, isNull);
+ } else {
+ expect(resynthesized.setter, isNotNull);
+ expect(resynthesized.setter.location, original.setter.location);
+ }
+ }
+
+ void compareTopLevelVariableElements(
+ TopLevelVariableElementImpl resynthesized,
+ TopLevelVariableElementImpl original,
+ String desc) {
+ comparePropertyInducingElements(resynthesized, original, desc);
+ }
+
+ void compareTypeImpls(
+ TypeImpl resynthesized, TypeImpl original, String desc) {
+ compareElementLocations(
+ resynthesized.element, original.element, '$desc.element.location');
+ expect(resynthesized.name, original.name, reason: '$desc.name');
+ }
+
+ void compareTypeParameterElementLists(
+ List<TypeParameterElement> resynthesized,
+ List<TypeParameterElement> original,
+ String desc) {
+ int length = original.length;
+ expect(resynthesized.length, length, reason: '$desc.length');
+ for (int i = 0; i < length; i++) {
+ compareTypeParameterElements(resynthesized[i], original[i], '$desc[$i]');
+ }
+ }
+
+ void compareTypeParameterElements(TypeParameterElement resynthesized,
+ TypeParameterElement original, String desc) {
+ compareElements(resynthesized, original, desc);
+ compareTypes(resynthesized.type, original.type, '$desc.type');
+ compareTypes(resynthesized.bound, original.bound, '$desc.bound');
+ }
+
+ void compareTypes(DartType resynthesized, DartType original, String desc) {
+ if (original == null) {
+ expect(resynthesized, isNull, reason: desc);
+ } else if (resynthesized is InterfaceTypeImpl &&
+ original is InterfaceTypeImpl) {
+ compareTypeImpls(resynthesized, original, desc);
+ expect(resynthesized.typeArguments.length, original.typeArguments.length,
+ reason: '$desc.typeArguments.length');
+ for (int i = 0; i < resynthesized.typeArguments.length; i++) {
+ compareTypes(resynthesized.typeArguments[i], original.typeArguments[i],
+ '$desc.typeArguments[$i] /* ${original.typeArguments[i].name} */');
+ }
+ } else if (resynthesized is TypeParameterTypeImpl &&
+ original is TypeParameterTypeImpl) {
+ compareTypeImpls(resynthesized, original, desc);
+ } else if (resynthesized is DynamicTypeImpl &&
+ original is DynamicTypeImpl) {
+ expect(resynthesized, same(original));
+ } else if (resynthesized is UndefinedTypeImpl &&
+ original is UndefinedTypeImpl) {
+ expect(resynthesized, same(original));
+ } else if (resynthesized is FunctionTypeImpl &&
+ original is FunctionTypeImpl) {
+ compareTypeImpls(resynthesized, original, desc);
+ expect(resynthesized.isInstantiated, original.isInstantiated,
+ reason: desc);
+ if (original.element.enclosingElement == null &&
+ original.element is FunctionElement) {
+ expect(resynthesized.element, new TypeMatcher<FunctionElement>());
+ expect(resynthesized.element.enclosingElement, isNull, reason: desc);
+ compareFunctionElements(
+ resynthesized.element, original.element, '$desc.element',
+ shallow: true);
+ expect(resynthesized.element.type, same(resynthesized));
+ }
+ expect(resynthesized.typeArguments.length, original.typeArguments.length,
+ reason: '$desc.typeArguments.length');
+ for (int i = 0; i < resynthesized.typeArguments.length; i++) {
+ if (resynthesized.typeArguments[i].isDynamic &&
+ original.typeArguments[i] is TypeParameterType) {
+ // It's ok for type arguments to get converted to `dynamic` if they
+ // are not used.
+ expect(
+ isTypeParameterUsed(
+ original.typeArguments[i], original.element.type),
+ isFalse);
+ } else {
+ compareTypes(
+ resynthesized.typeArguments[i],
+ original.typeArguments[i],
+ '$desc.typeArguments[$i] /* ${original.typeArguments[i].name} */');
+ }
+ }
+ if (original.typeParameters == null) {
+ expect(resynthesized.typeParameters, isNull, reason: desc);
+ } else {
+ expect(resynthesized.typeParameters, isNotNull, reason: desc);
+ expect(
+ resynthesized.typeParameters.length, original.typeParameters.length,
+ reason: desc);
+ for (int i = 0; i < resynthesized.typeParameters.length; i++) {
+ compareTypeParameterElements(resynthesized.typeParameters[i],
+ original.typeParameters[i], '$desc.typeParameters[$i]');
+ }
+ }
+ expect(resynthesized.typeFormals.length, original.typeFormals.length,
+ reason: desc);
+ for (int i = 0; i < resynthesized.typeFormals.length; i++) {
+ compareTypeParameterElements(resynthesized.typeFormals[i],
+ original.typeFormals[i], '$desc.typeFormals[$i]');
+ }
+ } else if (resynthesized is VoidTypeImpl && original is VoidTypeImpl) {
+ expect(resynthesized, same(original));
+ } else if (resynthesized is DynamicTypeImpl &&
+ original is UndefinedTypeImpl) {
+ // TODO(scheglov) In the strong mode constant variable like
+ // `var V = new Unresolved()` gets `UndefinedTypeImpl`, and it gets
+ // `DynamicTypeImpl` in the spec mode.
+ } else if (resynthesized is BottomTypeImpl && original is BottomTypeImpl) {
+ expect(resynthesized, same(original));
+ } else if (resynthesized.runtimeType != original.runtimeType) {
+ fail('Type mismatch: expected $original,'
+ ' got $resynthesized ($desc)');
+ } else {
+ fail('Unimplemented comparison for ${original.runtimeType}');
+ }
+ }
+
+ void compareVariableElements(
+ VariableElement resynthesized, VariableElement original, String desc) {
+ compareElements(resynthesized, original, desc);
+ if ((resynthesized as VariableElementImpl).typeInferenceError == null) {
+ compareTypes(resynthesized.type, original.type, '$desc.type');
+ }
+ VariableElementImpl resynthesizedActual =
+ getActualElement(resynthesized, desc);
+ VariableElementImpl originalActual = getActualElement(original, desc);
+ compareFunctionElements(resynthesizedActual.initializer,
+ originalActual.initializer, '$desc.initializer');
+ if (originalActual is ConstVariableElement) {
+ Element oEnclosing = original.enclosingElement;
+ if (oEnclosing is ClassElement && oEnclosing.isEnum) {
+ compareConstValues(resynthesized.constantValue, original.constantValue,
+ '$desc.constantValue');
+ } else {
+ Expression initializer = resynthesizedActual.constantInitializer;
+ if (variablesWithNotConstInitializers.contains(resynthesized.name)) {
+ expect(initializer, isNull, reason: desc);
+ } else {
+ compareConstAsts(initializer, originalActual.constantInitializer,
+ '$desc.constantInitializer');
+ }
+ }
+ }
+ checkPossibleMember(resynthesized, original, desc);
+ checkPossibleLocalElements(resynthesized, original);
+ }
+
+ ElementImpl getActualElement(Element element, String desc) {
+ if (element == null) {
+ return null;
+ } else if (element is ElementImpl) {
+ return element;
+ } else if (element is ElementHandle) {
+ Element actualElement = element.actualElement;
+ // A handle should never point to a member, because if it did, then
+ // "is Member" checks on the handle would produce the wrong result.
+ expect(actualElement, isNot(new TypeMatcher<Member>()), reason: desc);
+ return getActualElement(actualElement, desc);
+ } else if (element is Member) {
+ return getActualElement(element.baseElement, desc);
+ } else {
+ fail('Unexpected type for resynthesized ($desc):'
+ ' ${element.runtimeType}');
+ }
+ }
+
+ /**
+ * Determine if [type] makes use of the given [typeParameter].
+ */
+ bool isTypeParameterUsed(TypeParameterType typeParameter, DartType type) {
+ if (type is FunctionType) {
+ return isTypeParameterUsed(typeParameter, type.returnType) ||
+ type.parameters.any((ParameterElement e) =>
+ isTypeParameterUsed(typeParameter, e.type));
+ } else if (type is InterfaceType) {
+ return type.typeArguments
+ .any((DartType t) => isTypeParameterUsed(typeParameter, t));
+ } else if (type is TypeParameterType) {
+ return type == typeParameter;
+ } else {
+ expect(type.isDynamic || type.isVoid, isTrue);
+ return false;
+ }
+ }
+
+ LibraryElementImpl _encodeDecodeLibraryElement(Source source) {
+ SummaryResynthesizer resynthesizer = encodeLibrary(source);
+ return resynthesizer.getLibraryElement(source.uri.toString());
+ }
+
+ List<PropertyAccessorElement> _getSortedPropertyAccessors(
+ ClassElement classElement) {
+ List<PropertyAccessorElement> accessors = classElement.accessors.toList();
+ accessors.sort((a, b) => a.displayName.compareTo(b.displayName));
+ return accessors;
+ }
+
+ bool _hasModifier(Element element, Modifier modifier) {
+ if (modifier == Modifier.ABSTRACT) {
+ if (element is ClassElement) {
+ return element.isAbstract;
+ }
+ if (element is ExecutableElement) {
+ return element.isAbstract;
+ }
+ return false;
+ } else if (modifier == Modifier.ASYNCHRONOUS) {
+ if (element is ExecutableElement) {
+ return element.isAsynchronous;
+ }
+ return false;
+ } else if (modifier == Modifier.CONST) {
+ if (element is VariableElement) {
+ return element.isConst;
+ }
+ return false;
+ } else if (modifier == Modifier.COVARIANT) {
+ if (element is ParameterElementImpl) {
+ return element.isExplicitlyCovariant;
+ }
+ return false;
+ } else if (modifier == Modifier.DEFERRED) {
+ if (element is ImportElement) {
+ return element.isDeferred;
+ }
+ return false;
+ } else if (modifier == Modifier.ENUM) {
+ if (element is ClassElement) {
+ return element.isEnum;
+ }
+ return false;
+ } else if (modifier == Modifier.EXTERNAL) {
+ if (element is ExecutableElement) {
+ return element.isExternal;
+ }
+ return false;
+ } else if (modifier == Modifier.FACTORY) {
+ if (element is ConstructorElement) {
+ return element.isFactory;
+ }
+ return false;
+ } else if (modifier == Modifier.FINAL) {
+ if (element is VariableElement) {
+ return element.isFinal;
+ }
+ return false;
+ } else if (modifier == Modifier.GENERATOR) {
+ if (element is ExecutableElement) {
+ return element.isGenerator;
+ }
+ return false;
+ } else if (modifier == Modifier.GETTER) {
+ if (element is PropertyAccessorElement) {
+ return element.isGetter;
+ }
+ return false;
+ } else if (modifier == Modifier.HAS_EXT_URI) {
+ if (element is LibraryElement) {
+ return element.hasExtUri;
+ }
+ return false;
+ } else if (modifier == Modifier.IMPLICIT_TYPE) {
+ if (element is ExecutableElement) {
+ return element.hasImplicitReturnType;
+ }
+ return false;
+ } else if (modifier == Modifier.MIXIN_APPLICATION) {
+ if (element is ClassElement) {
+ return element.isMixinApplication;
+ }
+ return false;
+ } else if (modifier == Modifier.REFERENCES_SUPER) {
+ if (element is ClassElement) {
+ return element.hasReferenceToSuper;
+ }
+ return false;
+ } else if (modifier == Modifier.SETTER) {
+ if (element is PropertyAccessorElement) {
+ return element.isSetter;
+ }
+ return false;
+ } else if (modifier == Modifier.STATIC) {
+ if (element is ExecutableElement) {
+ return element.isStatic;
+ } else if (element is FieldElement) {
+ return element.isStatic;
+ }
+ return false;
+ } else if (modifier == Modifier.SYNTHETIC) {
+ return element.isSynthetic;
+ }
+ throw new UnimplementedError(
+ 'Modifier $modifier for ${element?.runtimeType}');
+ }
}
class TestSummaryResynthesizer extends SummaryResynthesizer {
diff --git a/pkg/analyzer/test/src/summary/test_strategies.dart b/pkg/analyzer/test/src/summary/test_strategies.dart
index 817e326..8a5da25 100644
--- a/pkg/analyzer/test/src/summary/test_strategies.dart
+++ b/pkg/analyzer/test/src/summary/test_strategies.dart
@@ -4,9 +4,13 @@
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/memory_file_system.dart';
+import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -18,10 +22,13 @@
import 'package:analyzer/src/summary/prelink.dart';
import 'package:analyzer/src/summary/summarize_ast.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
+import 'package:analyzer/src/task/api/dart.dart';
+import 'package:analyzer/src/task/api/general.dart';
import 'package:path/path.dart' show posix;
import 'package:test/test.dart';
import '../context/mock_sdk.dart';
+import 'resynthesize_common.dart';
/// Convert the given Posix style file [path] to the corresponding absolute URI.
String absUri(String path) {
@@ -75,6 +82,164 @@
}
}
+/// Abstract base class for tests of summary resynthesis.
+///
+/// Test classes should not extend this class directly; they should extend a
+/// class that implements this class with methods that drive summary generation.
+/// The tests themselves can then be provided via mixin, allowing summaries to
+/// be tested in a variety of ways.
+abstract class ResynthesizeTestStrategy {
+ //Future<LibraryElementImpl> checkLibrary(String text,
+ // {bool allowErrors: false, bool dumpSummaries: false});
+
+ void set allowMissingFiles(bool value);
+
+ AnalysisContextImpl get context;
+
+ MemoryResourceProvider get resourceProvider;
+
+ void set testFile(String value);
+
+ Source get testSource;
+
+ void addLibrary(String uri);
+
+ Source addLibrarySource(String filePath, String contents);
+
+ Source addSource(String path, String contents);
+
+ Source addTestSource(String code, [Uri uri]);
+
+ void checkMinimalResynthesisWork(
+ TestSummaryResynthesizer resynthesizer, LibraryElement library);
+
+ TestSummaryResynthesizer encodeLibrary(Source source);
+
+ void prepareAnalysisContext([AnalysisOptions options]);
+}
+
+/// Implementation of [SummaryBlackBoxTestStrategy] that drives summary
+/// generation using the old two-phase API.
+class ResynthesizeTestStrategyTwoPhase extends AbstractResynthesizeTest
+ implements ResynthesizeTestStrategy {
+ final Set<Source> serializedSources = new Set<Source>();
+
+ final Map<String, UnlinkedUnitBuilder> uriToUnit =
+ <String, UnlinkedUnitBuilder>{};
+
+ PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
+
+ 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 && !allowMissingFiles) {
+ 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 && !allowMissingFiles) {
+ fail('Linker unexpectedly requested unit for "$absoluteUri".');
+ }
+ return unit;
+ }
+
+ Set<String> nonSdkLibraryUris = serializedSources
+ .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.declaredVariables.get);
+
+ return new TestSummaryResynthesizer(
+ context,
+ new Map<String, UnlinkedUnit>()
+ ..addAll(SerializedMockSdk.instance.uriToUnlinkedUnit)
+ ..addAll(unlinkedSummaries),
+ new Map<String, LinkedLibrary>()
+ ..addAll(SerializedMockSdk.instance.uriToLinkedLibrary)
+ ..addAll(linkedSummaries),
+ allowMissingFiles);
+ }
+
+ UnlinkedUnit _getUnlinkedUnit(Source source) {
+ if (source == null) {
+ return new UnlinkedUnitBuilder();
+ }
+
+ String uriStr = source.uri.toString();
+ {
+ UnlinkedUnit unlinkedUnitInSdk =
+ SerializedMockSdk.instance.uriToUnlinkedUnit[uriStr];
+ if (unlinkedUnitInSdk != null) {
+ return unlinkedUnitInSdk;
+ }
+ }
+ return uriToUnit.putIfAbsent(uriStr, () {
+ int modificationTime = context.computeResult(source, MODIFICATION_TIME);
+ if (modificationTime < 0) {
+ // Source does not exist.
+ if (!allowMissingFiles) {
+ fail('Unexpectedly tried to get unlinked summary for $source');
+ }
+ return null;
+ }
+ CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
+ UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
+ bundleAssembler.addUnlinkedUnit(source, unlinkedUnit);
+ return unlinkedUnit;
+ });
+ }
+
+ void _serializeLibrary(Source librarySource) {
+ if (librarySource == null || librarySource.isInSystemLibrary) {
+ return;
+ }
+ if (!serializedSources.add(librarySource)) {
+ return;
+ }
+
+ UnlinkedUnit getPart(String absoluteUri) {
+ Source source = context.sourceFactory.forUri(absoluteUri);
+ return _getUnlinkedUnit(source);
+ }
+
+ UnlinkedPublicNamespace getImport(String relativeUri) {
+ return getPart(relativeUri)?.publicNamespace;
+ }
+
+ UnlinkedUnit definingUnit = _getUnlinkedUnit(librarySource);
+ if (definingUnit != null) {
+ LinkedLibraryBuilder linkedLibrary = prelink(librarySource.uri.toString(),
+ definingUnit, getPart, getImport, context.declaredVariables.get);
+ linkedLibrary.dependencies.skip(1).forEach((LinkedDependency d) {
+ Source source = context.sourceFactory.forUri(d.uri);
+ _serializeLibrary(source);
+ });
+ }
+ }
+}
+
/// [SerializedMockSdk] is a singleton class representing the result of
/// serializing the mock SDK to summaries. It is computed once and then shared
/// among test invocations so that we don't bog down the tests.