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.