// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';
import 'dart:math' show min;

import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/constant/compute.dart';
import 'package:analyzer/src/dart/constant/evaluation.dart';
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
import 'package:analyzer/src/generated/engine.dart'
    show AnalysisContext, AnalysisEngine, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/linked_unit_context.dart';
import 'package:analyzer/src/summary2/reference.dart';

/// Assert that the given [object] is null, which in the places where this
/// function is called means that the element is not resynthesized.
void _assertNotResynthesized(Object object) {
  // TODO(scheglov) I comment this check for now.
  // When we make a decision about switch to the new analysis driver,
  // we will need to rework the analysis code to don't call the setters
  // or restore / inline it.
//  assert(object == null);
}

/// A concrete implementation of a [ClassElement].
abstract class AbstractClassElementImpl extends ElementImpl
    implements ClassElement {
  /// A list containing all of the accessors (getters and setters) contained in
  /// this class.
  List<PropertyAccessorElement> _accessors;

  /// A list containing all of the fields contained in this class.
  List<FieldElement> _fields;

  /// A list containing all of the methods contained in this class.
  List<MethodElement> _methods;

  /// Initialize a newly created class element to have the given [name] at the
  /// given [offset] in the file that contains the declaration of this element.
  AbstractClassElementImpl(String name, int offset) : super(name, offset);

  AbstractClassElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created class element to have the given [name].
  AbstractClassElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  AbstractClassElementImpl.forSerialized(
      CompilationUnitElementImpl enclosingUnit)
      : super.forSerialized(enclosingUnit);

  @override
  List<PropertyAccessorElement> get accessors {
    return _accessors ?? const <PropertyAccessorElement>[];
  }

  /// Set the accessors contained in this class to the given [accessors].
  void set accessors(List<PropertyAccessorElement> accessors) {
    for (PropertyAccessorElement accessor in accessors) {
      (accessor as PropertyAccessorElementImpl).enclosingElement = this;
    }
    this._accessors = accessors;
  }

  @override
  String get displayName => name;

  @override
  List<FieldElement> get fields => _fields ?? const <FieldElement>[];

  /// Set the fields contained in this class to the given [fields].
  void set fields(List<FieldElement> fields) {
    for (FieldElement field in fields) {
      (field as FieldElementImpl).enclosingElement = this;
    }
    this._fields = fields;
  }

  @override
  bool get isEnum => false;

  @override
  bool get isMixin => false;

  @override
  ElementKind get kind => ElementKind.CLASS;

  @override
  List<InterfaceType> get superclassConstraints => const <InterfaceType>[];

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitClassElement(this);

  @deprecated
  @override
  NamedCompilationUnitMember computeNode() {
    if (isEnum) {
      return getNodeMatching((node) => node is EnumDeclaration);
    } else {
      return getNodeMatching(
          (node) => node is ClassDeclaration || node is ClassTypeAlias);
    }
  }

  @override
  ElementImpl getChild(String identifier) {
    //
    // The casts in this method are safe because the set methods would have
    // thrown a CCE if any of the elements in the arrays were not of the
    // expected types.
    //
    for (PropertyAccessorElement accessor in accessors) {
      PropertyAccessorElementImpl accessorImpl = accessor;
      if (accessorImpl.identifier == identifier) {
        return accessorImpl;
      }
    }
    for (FieldElement field in fields) {
      FieldElementImpl fieldImpl = field;
      if (fieldImpl.identifier == identifier) {
        return fieldImpl;
      }
    }
    return null;
  }

  @override
  FieldElement getField(String name) {
    for (FieldElement fieldElement in fields) {
      if (name == fieldElement.name) {
        return fieldElement;
      }
    }
    return null;
  }

  @override
  PropertyAccessorElement getGetter(String getterName) {
    int length = accessors.length;
    for (int i = 0; i < length; i++) {
      PropertyAccessorElement accessor = accessors[i];
      if (accessor.isGetter && accessor.name == getterName) {
        return accessor;
      }
    }
    return null;
  }

  @override
  MethodElement getMethod(String methodName) {
    int length = methods.length;
    for (int i = 0; i < length; i++) {
      MethodElement method = methods[i];
      if (method.name == methodName) {
        return method;
      }
    }
    return null;
  }

  @override
  PropertyAccessorElement getSetter(String setterName) {
    return getSetterFromAccessors(setterName, accessors);
  }

  @override
  MethodElement lookUpConcreteMethod(
          String methodName, LibraryElement library) =>
      _first(getImplementationsOfMethod(this, methodName).where(
          (MethodElement method) =>
              !method.isAbstract && method.isAccessibleIn(library)));

  @override
  PropertyAccessorElement lookUpGetter(
          String getterName, LibraryElement library) =>
      _first(_implementationsOfGetter(getterName).where(
          (PropertyAccessorElement getter) => getter.isAccessibleIn(library)));

  @override
  PropertyAccessorElement lookUpInheritedConcreteGetter(
          String getterName, LibraryElement library) =>
      _first(_implementationsOfGetter(getterName).where(
          (PropertyAccessorElement getter) =>
              !getter.isAbstract &&
              getter.isAccessibleIn(library) &&
              getter.enclosingElement != this));

  ExecutableElement lookUpInheritedConcreteMember(
      String name, LibraryElement library) {
    if (name.endsWith('=')) {
      return lookUpInheritedConcreteSetter(name, library);
    } else {
      return lookUpInheritedConcreteMethod(name, library) ??
          lookUpInheritedConcreteGetter(name, library);
    }
  }

  @override
  MethodElement lookUpInheritedConcreteMethod(
          String methodName, LibraryElement library) =>
      _first(getImplementationsOfMethod(this, methodName).where(
          (MethodElement method) =>
              !method.isAbstract &&
              method.isAccessibleIn(library) &&
              method.enclosingElement != this));

  @override
  PropertyAccessorElement lookUpInheritedConcreteSetter(
          String setterName, LibraryElement library) =>
      _first(_implementationsOfSetter(setterName).where(
          (PropertyAccessorElement setter) =>
              !setter.isAbstract &&
              setter.isAccessibleIn(library) &&
              setter.enclosingElement != this));

  @override
  MethodElement lookUpInheritedMethod(
          String methodName, LibraryElement library) =>
      _first(getImplementationsOfMethod(this, methodName).where(
          (MethodElement method) =>
              method.isAccessibleIn(library) &&
              method.enclosingElement != this));

  @override
  MethodElement lookUpMethod(String methodName, LibraryElement library) =>
      lookUpMethodInClass(this, methodName, library);

  @override
  PropertyAccessorElement lookUpSetter(
          String setterName, LibraryElement library) =>
      _first(_implementationsOfSetter(setterName).where(
          (PropertyAccessorElement setter) => setter.isAccessibleIn(library)));

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    safelyVisitChildren(accessors, visitor);
    safelyVisitChildren(fields, visitor);
  }

  /// Return an iterable containing all of the implementations of a getter with
  /// the given [getterName] that are defined in this class any any superclass
  /// of this class (but not in interfaces).
  ///
  /// The getters that are returned are not filtered in any way. In particular,
  /// they can include getters that are not visible in some context. Clients
  /// must perform any necessary filtering.
  ///
  /// The getters are returned based on the depth of their defining class; if
  /// this class contains a definition of the getter it will occur first, if
  /// Object contains a definition of the getter it will occur last.
  Iterable<PropertyAccessorElement> _implementationsOfGetter(
      String getterName) sync* {
    ClassElement classElement = this;
    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
    while (classElement != null && visitedClasses.add(classElement)) {
      PropertyAccessorElement getter = classElement.getGetter(getterName);
      if (getter != null) {
        yield getter;
      }
      for (InterfaceType mixin in classElement.mixins.reversed) {
        getter = mixin.element?.getGetter(getterName);
        if (getter != null) {
          yield getter;
        }
      }
      classElement = classElement.supertype?.element;
    }
  }

  /// Return an iterable containing all of the implementations of a setter with
  /// the given [setterName] that are defined in this class any any superclass
  /// of this class (but not in interfaces).
  ///
  /// The setters that are returned are not filtered in any way. In particular,
  /// they can include setters that are not visible in some context. Clients
  /// must perform any necessary filtering.
  ///
  /// The setters are returned based on the depth of their defining class; if
  /// this class contains a definition of the setter it will occur first, if
  /// Object contains a definition of the setter it will occur last.
  Iterable<PropertyAccessorElement> _implementationsOfSetter(
      String setterName) sync* {
    ClassElement classElement = this;
    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
    while (classElement != null && visitedClasses.add(classElement)) {
      PropertyAccessorElement setter = classElement.getSetter(setterName);
      if (setter != null) {
        yield setter;
      }
      for (InterfaceType mixin in classElement.mixins.reversed) {
        setter = mixin.element?.getSetter(setterName);
        if (setter != null) {
          yield setter;
        }
      }
      classElement = classElement.supertype?.element;
    }
  }

  /// Return the [AbstractClassElementImpl] of the given [classElement].  May
  /// throw an exception if the [AbstractClassElementImpl] cannot be provided
  /// (should not happen though).
  static AbstractClassElementImpl getImpl(ClassElement classElement) {
    if (classElement is ClassElementHandle) {
      return getImpl(classElement.actualElement);
    }
    return classElement as AbstractClassElementImpl;
  }

  /// Return an iterable containing all of the implementations of a method with
  /// the given [methodName] that are defined in this class any any superclass
  /// of this class (but not in interfaces).
  ///
  /// The methods that are returned are not filtered in any way. In particular,
  /// they can include methods that are not visible in some context. Clients
  /// must perform any necessary filtering.
  ///
  /// The methods are returned based on the depth of their defining class; if
  /// this class contains a definition of the method it will occur first, if
  /// Object contains a definition of the method it will occur last.
  static Iterable<MethodElement> getImplementationsOfMethod(
      ClassElement classElement, String methodName) sync* {
    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
    while (classElement != null && visitedClasses.add(classElement)) {
      MethodElement method = classElement.getMethod(methodName);
      if (method != null) {
        yield method;
      }
      for (InterfaceType mixin in classElement.mixins.reversed) {
        method = mixin.element?.getMethod(methodName);
        if (method != null) {
          yield method;
        }
      }
      classElement = classElement.supertype?.element;
    }
  }

  static PropertyAccessorElement getSetterFromAccessors(
      String setterName, List<PropertyAccessorElement> accessors) {
    // TODO (jwren) revisit- should we append '=' here or require clients to
    // include it?
    // Do we need the check for isSetter below?
    if (!StringUtilities.endsWithChar(setterName, 0x3D)) {
      setterName += '=';
    }
    for (PropertyAccessorElement accessor in accessors) {
      if (accessor.isSetter && accessor.name == setterName) {
        return accessor;
      }
    }
    return null;
  }

  static MethodElement lookUpMethodInClass(
      ClassElement classElement, String methodName, LibraryElement library) {
    return _first(getImplementationsOfMethod(classElement, methodName)
        .where((MethodElement method) => method.isAccessibleIn(library)));
  }

  /// Return the first element from the given [iterable], or `null` if the
  /// iterable is empty.
  static E _first<E>(Iterable<E> iterable) {
    if (iterable.isEmpty) {
      return null;
    }
    return iterable.first;
  }
}

/// For AST nodes that could be in both the getter and setter contexts
/// ([IndexExpression]s and [SimpleIdentifier]s), the additional resolved
/// elements are stored in the AST node, in an [AuxiliaryElements]. Because
/// resolved elements are either statically resolved or resolved using
/// propagated type information, this class is a wrapper for a pair of
/// [ExecutableElement]s, not just a single [ExecutableElement].
class AuxiliaryElements {
  /// The element based on static type information, or `null` if the AST
  /// structure has not been resolved or if the node could not be resolved.
  final ExecutableElement staticElement;

  /// Initialize a newly created pair to have both the [staticElement] and
  /// `null`.
  AuxiliaryElements(this.staticElement, ExecutableElement propagatedElement);

  /// The element based on propagated type information, or `null` if the AST
  /// structure has not been resolved or if the node could not be resolved.
  ExecutableElement get propagatedElement => null;
}

/// An [AbstractClassElementImpl] which is a class.
class ClassElementImpl extends AbstractClassElementImpl
    with TypeParameterizedElementMixin, SimplyBoundableMixin {
  /// The unlinked representation of the class in the summary.
  final UnlinkedClass _unlinkedClass;

  /// If this class is resynthesized, whether it has a constant constructor.
  bool _hasConstConstructorCached;

  /// The superclass of the class, or `null` for [Object].
  InterfaceType _supertype;

  /// The type defined by the class.
  InterfaceType _type;

  /// A list containing all of the mixins that are applied to the class being
  /// extended in order to derive the superclass of this class.
  List<InterfaceType> _mixins;

  /// A list containing all of the interfaces that are implemented by this
  /// class.
  List<InterfaceType> _interfaces;

  /// For classes which are not mixin applications, a list containing all of the
  /// constructors contained in this class, or `null` if the list of
  /// constructors has not yet been built.
  ///
  /// For classes which are mixin applications, the list of constructors is
  /// computed on the fly by the [constructors] getter, and this field is
  /// `null`.
  List<ConstructorElement> _constructors;

  /// A flag indicating whether the types associated with the instance members
  /// of this class have been inferred.
  bool _hasBeenInferred = false;

  /// The version of this element. The version is changed when the element is
  /// incrementally updated, so that its lists of constructors, accessors and
  /// methods might be different.
  int version = 0;

  /// Initialize a newly created class element to have the given [name] at the
  /// given [offset] in the file that contains the declaration of this element.
  ClassElementImpl(String name, int offset)
      : _unlinkedClass = null,
        super(name, offset);

  ClassElementImpl.forLinkedNode(CompilationUnitElementImpl enclosing,
      Reference reference, LinkedNode linkedNode)
      : _unlinkedClass = null,
        super.forLinkedNode(enclosing, reference, linkedNode) {
    enclosing.linkedContext.loadClassMemberReferences(reference);
  }

  /// Initialize a newly created class element to have the given [name].
  ClassElementImpl.forNode(Identifier name)
      : _unlinkedClass = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  ClassElementImpl.forSerialized(
      this._unlinkedClass, CompilationUnitElementImpl enclosingUnit)
      : super.forSerialized(enclosingUnit);

  /// Set whether this class is abstract.
  void set abstract(bool isAbstract) {
    _assertNotResynthesized(_unlinkedClass);
    setModifier(Modifier.ABSTRACT, isAbstract);
  }

  @override
  List<PropertyAccessorElement> get accessors {
    if (linkedNode != null) {
      if (_accessors != null) return _accessors;

      if (linkedNode.kind == LinkedNodeKind.classDeclaration ||
          linkedNode.kind == LinkedNodeKind.mixinDeclaration) {
        _createPropertiesAndAccessors();
        assert(_accessors != null);
        return _accessors;
      } else {
        return _accessors = const [];
      }
    }
    if (_accessors == null) {
      if (_unlinkedClass != null) {
        _resynthesizeFieldsAndPropertyAccessors();
      }
    }
    return _accessors ?? const <PropertyAccessorElement>[];
  }

  @override
  void set accessors(List<PropertyAccessorElement> accessors) {
    _assertNotResynthesized(_unlinkedClass);
    super.accessors = accessors;
  }

  @override
  List<InterfaceType> get allSupertypes {
    List<InterfaceType> list = new List<InterfaceType>();
    collectAllSupertypes(list, type, type);
    return list;
  }

  @override
  int get codeLength {
    if (_unlinkedClass != null) {
      return _unlinkedClass.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (_unlinkedClass != null) {
      return _unlinkedClass.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  List<ConstructorElement> get constructors {
    if (_constructors != null) {
      return _constructors;
    }

    if (isMixinApplication) {
      return _constructors = _computeMixinAppConstructors();
    }

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@constructor');
      if (linkedNode.kind == LinkedNodeKind.classDeclaration) {
        _constructors = linkedNode.classOrMixinDeclaration_members
            .where((node) => node.kind == LinkedNodeKind.constructorDeclaration)
            .map((node) {
          var name = context.getConstructorDeclarationName(node);
          var reference = containerRef.getChild(name);
          return ConstructorElementImpl.forLinkedNode(reference, node, this);
        }).toList();
      }
    }

    if (_unlinkedClass != null) {
      var unlinkedExecutables = _unlinkedClass.executables;

      var length = unlinkedExecutables.length;
      if (length != 0) {
        var count = 0;
        for (var i = 0; i < length; i++) {
          var e = unlinkedExecutables[i];
          if (e.kind == UnlinkedExecutableKind.constructor) {
            count++;
          }
        }

        if (count != 0) {
          var constructors = new List<ConstructorElement>(count);
          var index = 0;
          for (var i = 0; i < length; i++) {
            var e = unlinkedExecutables[i];
            if (e.kind == UnlinkedExecutableKind.constructor) {
              constructors[index++] =
                  new ConstructorElementImpl.forSerialized(e, this);
            }
          }
          return _constructors = constructors;
        }
      }

      // There are no explicit constructors.
      // Create the implicit default constructor.
      var constructor = new ConstructorElementImpl('', -1);
      constructor.isSynthetic = true;
      constructor.enclosingElement = this;
      _constructors = <ConstructorElement>[constructor];
    }

    assert(_constructors != null);
    return _constructors ?? const <ConstructorElement>[];
  }

  /// Set the constructors contained in this class to the given [constructors].
  ///
  /// Should only be used for class elements that are not mixin applications.
  void set constructors(List<ConstructorElement> constructors) {
    _assertNotResynthesized(_unlinkedClass);
    assert(!isMixinApplication);
    for (ConstructorElement constructor in constructors) {
      (constructor as ConstructorElementImpl).enclosingElement = this;
    }
    this._constructors = constructors;
  }

  @override
  String get documentationComment {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getCommentText(
        linkedNode.annotatedNode_comment,
      );
    }
    if (_unlinkedClass != null) {
      return _unlinkedClass.documentationComment?.text;
    }
    return super.documentationComment;
  }

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;

  @override
  List<FieldElement> get fields {
    if (linkedNode != null) {
      if (_fields != null) return _fields;

      if (linkedNode.kind == LinkedNodeKind.classDeclaration ||
          linkedNode.kind == LinkedNodeKind.mixinDeclaration) {
        _createPropertiesAndAccessors();
        assert(_fields != null);
        return _fields;
      } else {
        _fields = const [];
      }
    }
    if (_fields == null) {
      if (_unlinkedClass != null) {
        _resynthesizeFieldsAndPropertyAccessors();
      }
    }
    return _fields ?? const <FieldElement>[];
  }

  @override
  void set fields(List<FieldElement> fields) {
    _assertNotResynthesized(_unlinkedClass);
    super.fields = fields;
  }

  bool get hasBeenInferred {
    return _unlinkedClass != null || _hasBeenInferred;
  }

  void set hasBeenInferred(bool hasBeenInferred) {
    _assertNotResynthesized(_unlinkedClass);
    _hasBeenInferred = hasBeenInferred;
  }

  @override
  bool get hasNonFinalField {
    List<ClassElement> classesToVisit = new List<ClassElement>();
    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
    classesToVisit.add(this);
    while (!classesToVisit.isEmpty) {
      ClassElement currentElement = classesToVisit.removeAt(0);
      if (visitedClasses.add(currentElement)) {
        // check fields
        for (FieldElement field in currentElement.fields) {
          if (!field.isFinal &&
              !field.isConst &&
              !field.isStatic &&
              !field.isSynthetic) {
            return true;
          }
        }
        // check mixins
        for (InterfaceType mixinType in currentElement.mixins) {
          ClassElement mixinElement = mixinType.element;
          classesToVisit.add(mixinElement);
        }
        // check super
        InterfaceType supertype = currentElement.supertype;
        if (supertype != null) {
          ClassElement superElement = supertype.element;
          if (superElement != null) {
            classesToVisit.add(superElement);
          }
        }
      }
    }
    // not found
    return false;
  }

  /// Return `true` if the class has a concrete `noSuchMethod()` method distinct
  /// from the one declared in class `Object`, as per the Dart Language
  /// Specification (section 10.4).
  bool get hasNoSuchMethod {
    MethodElement method = lookUpConcreteMethod(
        FunctionElement.NO_SUCH_METHOD_METHOD_NAME, library);
    ClassElement definingClass = method?.enclosingElement;
    return definingClass != null && !definingClass.type.isObject;
  }

  @override
  bool get hasReferenceToSuper => hasModifier(Modifier.REFERENCES_SUPER);

  /// Set whether this class references 'super'.
  void set hasReferenceToSuper(bool isReferencedSuper) {
    setModifier(Modifier.REFERENCES_SUPER, isReferencedSuper);
  }

  @override
  bool get hasStaticMember {
    for (MethodElement method in methods) {
      if (method.isStatic) {
        return true;
      }
    }
    for (PropertyAccessorElement accessor in accessors) {
      if (accessor.isStatic) {
        return true;
      }
    }
    return false;
  }

  @override
  List<InterfaceType> get interfaces {
    if (_interfaces != null) {
      return _interfaces;
    }

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var implementsClause = context.getImplementsClause(linkedNode);
      if (implementsClause != null) {
        return _interfaces = implementsClause.implementsClause_interfaces
            .map((node) => context.getInterfaceType(node.typeName_type))
            .where((type) => type != null)
            .toList();
      }
    } else if (_unlinkedClass != null) {
      var unlinkedInterfaces = _unlinkedClass.interfaces;
      var length = unlinkedInterfaces.length;
      if (length == 0) {
        return _interfaces = const <InterfaceType>[];
      }

      ResynthesizerContext context = enclosingUnit.resynthesizerContext;
      var interfaces = new List<InterfaceType>(length);
      var index = 0;
      var hasNonInterfaceType = false;
      for (var i = 0; i < length; i++) {
        var t = unlinkedInterfaces[i];
        var type = context.resolveTypeRef(this, t);
        if (_isInterfaceTypeInterface(type)) {
          interfaces[index++] = type;
        } else {
          hasNonInterfaceType = true;
        }
      }

      if (hasNonInterfaceType) {
        interfaces = interfaces.sublist(0, index);
      }

      return _interfaces = interfaces;
    }

    return _interfaces = const <InterfaceType>[];
  }

  void set interfaces(List<InterfaceType> interfaces) {
    _assertNotResynthesized(_unlinkedClass);
    _interfaces = interfaces;
  }

  @override
  bool get isAbstract {
    if (linkedNode != null) {
      if (linkedNode.kind == LinkedNodeKind.classDeclaration) {
        return linkedNode.classDeclaration_abstractKeyword != 0;
      } else {
        return linkedNode.classTypeAlias_abstractKeyword != 0;
      }
    }
    if (_unlinkedClass != null) {
      return _unlinkedClass.isAbstract;
    }
    return hasModifier(Modifier.ABSTRACT);
  }

  @override
  bool get isMixinApplication {
    if (linkedNode != null) {
      return linkedNode.kind == LinkedNodeKind.classTypeAlias;
    }
    if (_unlinkedClass != null) {
      return _unlinkedClass.isMixinApplication;
    }
    return hasModifier(Modifier.MIXIN_APPLICATION);
  }

  @override
  bool get isOrInheritsProxy =>
      _safeIsOrInheritsProxy(this, new HashSet<ClassElement>());

  @override
  bool get isProxy {
    for (ElementAnnotation annotation in metadata) {
      if (annotation.isProxy) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get isValidMixin {
    if (hasReferenceToSuper) {
      return false;
    }
    if (!supertype.isObject) {
      return false;
    }
    for (ConstructorElement constructor in constructors) {
      if (!constructor.isSynthetic && !constructor.isFactory) {
        return false;
      }
    }
    return true;
  }

  @override
  List<ElementAnnotation> get metadata {
    if (_unlinkedClass != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, _unlinkedClass.annotations);
    }
    return super.metadata;
  }

  @override
  List<MethodElement> get methods {
    if (_methods != null) {
      return _methods;
    }

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@method');
      if (linkedNode.kind == LinkedNodeKind.classDeclaration ||
          linkedNode.kind == LinkedNodeKind.mixinDeclaration) {
        return _methods = linkedNode.classOrMixinDeclaration_members
            .where((node) => node.kind == LinkedNodeKind.methodDeclaration)
            .where((node) => node.methodDeclaration_propertyKeyword == 0)
            .map((node) {
          var name = context.getSimpleName(node.methodDeclaration_name);
          var reference = containerRef.getChild(name);
          return MethodElementImpl.forLinkedNode(reference, node, this);
        }).toList();
      } else {
        return _methods = const <MethodElement>[];
      }
    }

    if (_unlinkedClass != null) {
      var unlinkedExecutables = _unlinkedClass.executables;

      var length = unlinkedExecutables.length;
      if (length == 0) {
        return _methods = const <MethodElement>[];
      }

      var count = 0;
      for (var i = 0; i < length; i++) {
        var e = unlinkedExecutables[i];
        if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
          count++;
        }
      }
      if (count == 0) {
        return _methods = const <MethodElement>[];
      }

      var methods = new List<MethodElement>(count);
      var index = 0;
      for (var i = 0; i < length; i++) {
        var e = unlinkedExecutables[i];
        if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
          methods[index++] = new MethodElementImpl.forSerialized(e, this);
        }
      }
      return _methods = methods;
    }
    return _methods = const <MethodElement>[];
  }

  /// Set the methods contained in this class to the given [methods].
  void set methods(List<MethodElement> methods) {
    _assertNotResynthesized(_unlinkedClass);
    for (MethodElement method in methods) {
      (method as MethodElementImpl).enclosingElement = this;
    }
    _methods = methods;
  }

  /// Set whether this class is a mixin application.
  void set mixinApplication(bool isMixinApplication) {
    _assertNotResynthesized(_unlinkedClass);
    setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
  }

  @override
  List<InterfaceType> get mixins {
    if (_mixins != null) {
      return _mixins;
    }

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      LinkedNode withClause;
      if (linkedNode.kind == LinkedNodeKind.classDeclaration) {
        withClause = linkedNode.classDeclaration_withClause;
      } else {
        withClause = linkedNode.classTypeAlias_withClause;
      }
      if (withClause != null) {
        return _mixins = withClause.withClause_mixinTypes
            .map((node) => context.getInterfaceType(node.typeName_type))
            .where((type) => type != null)
            .toList();
      }
    } else if (_unlinkedClass != null) {
      var unlinkedMixins = _unlinkedClass.mixins;
      var length = unlinkedMixins.length;
      if (length == 0) {
        return _mixins = const <InterfaceType>[];
      }

      ResynthesizerContext context = enclosingUnit.resynthesizerContext;
      var mixins = new List<InterfaceType>(length);
      var index = 0;
      var hasNonInterfaceType = false;
      for (var i = 0; i < length; i++) {
        var t = unlinkedMixins[i];
        var type = context.resolveTypeRef(this, t);
        if (_isInterfaceTypeInterface(type)) {
          mixins[index++] = type;
        } else {
          hasNonInterfaceType = true;
        }
      }

      if (hasNonInterfaceType) {
        mixins = mixins.sublist(0, index);
      }

      return _mixins = mixins;
    }

    return _mixins = const <InterfaceType>[];
  }

  void set mixins(List<InterfaceType> mixins) {
    _assertNotResynthesized(_unlinkedClass);
    // Note: if we are using the analysis driver, the set of mixins has already
    // been computed, and it's more accurate (since mixin arguments have been
    // inferred).  So we only store mixins if we are using the old task model.
    if (_unlinkedClass == null) {
      _mixins = mixins;
    }
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (_unlinkedClass != null) {
      return _unlinkedClass.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedClass != null) {
      return _unlinkedClass.nameOffset;
    }
    return offset;
  }

  /// Names of methods, getters, setters, and operators that this mixin
  /// declaration super-invokes.  For setters this includes the trailing "=".
  /// The list will be empty if this class is not a mixin declaration.
  List<String> get superInvokedNames => const <String>[];

  @override
  InterfaceType get supertype {
    if (_supertype == null) {
      if (linkedNode != null) {
        LinkedNode superclass;
        if (linkedNode.kind == LinkedNodeKind.classDeclaration) {
          superclass = linkedNode
              .classDeclaration_extendsClause?.extendsClause_superclass;
        } else {
          superclass = linkedNode.classTypeAlias_superclass;
        }
        if (superclass != null) {
          var context = enclosingUnit.linkedContext;
          _supertype = context.getInterfaceType(superclass.typeName_type);
        } else if (!linkedNode.classDeclaration_isDartObject) {
          _supertype = context.typeProvider.objectType;
        }
      } else if (_unlinkedClass != null) {
        if (_unlinkedClass.supertype != null) {
          DartType type = enclosingUnit.resynthesizerContext
              .resolveTypeRef(this, _unlinkedClass.supertype);
          if (_isInterfaceTypeClass(type)) {
            _supertype = type;
          } else {
            _supertype = context.typeProvider.objectType;
          }
        } else if (_unlinkedClass.hasNoSupertype) {
          return null;
        } else {
          _supertype = context.typeProvider.objectType;
        }
      }
    }
    return _supertype;
  }

  void set supertype(InterfaceType supertype) {
    _assertNotResynthesized(_unlinkedClass);
    _supertype = supertype;
  }

  @override
  InterfaceType get type {
    if (_type == null) {
      InterfaceTypeImpl type = new InterfaceTypeImpl(this);
      type.typeArguments = typeParameterTypes;
      _type = type;
    }
    return _type;
  }

  @override
  List<TypeParameterElement> get typeParameters {
    if (_typeParameterElements != null) return _typeParameterElements;

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@typeParameter');
      var typeParameters = context.getTypeParameters(linkedNode);
      if (typeParameters == null) {
        return _typeParameterElements = const [];
      }
      return _typeParameterElements = typeParameters.map((node) {
        var name = context.getSimpleName(node.typeParameter_name);
        var reference = containerRef.getChild(name);
        reference.node = node;
        return TypeParameterElementImpl.forLinkedNode(this, reference, node);
      }).toList();
    }
    return super.typeParameters;
  }

  /// Set the type parameters defined for this class to the given
  /// [typeParameters].
  void set typeParameters(List<TypeParameterElement> typeParameters) {
    _assertNotResynthesized(_unlinkedClass);
    for (TypeParameterElement typeParameter in typeParameters) {
      (typeParameter as TypeParameterElementImpl).enclosingElement = this;
    }
    this._typeParameterElements = typeParameters;
  }

  @override
  List<UnlinkedTypeParam> get unlinkedTypeParams =>
      _unlinkedClass?.typeParameters;

  @override
  ConstructorElement get unnamedConstructor {
    for (ConstructorElement element in constructors) {
      String name = element.displayName;
      if (name == null || name.isEmpty) {
        return element;
      }
    }
    return null;
  }

  /// Return whether the class is resynthesized and has a constant constructor.
  bool get _hasConstConstructor {
    if (_hasConstConstructorCached == null) {
      _hasConstConstructorCached = false;
      if (_unlinkedClass != null) {
        _hasConstConstructorCached = _unlinkedClass.executables.any(
            (c) => c.kind == UnlinkedExecutableKind.constructor && c.isConst);
      }
    }
    return _hasConstConstructorCached;
  }

  @override
  int get _notSimplyBoundedSlot => _unlinkedClass?.notSimplyBoundedSlot;

  @override
  void appendTo(StringBuffer buffer) {
    if (isAbstract) {
      buffer.write('abstract ');
    }
    buffer.write('class ');
    String name = displayName;
    if (name == null) {
      buffer.write("{unnamed class}");
    } else {
      buffer.write(name);
    }
    int variableCount = typeParameters.length;
    if (variableCount > 0) {
      buffer.write("<");
      for (int i = 0; i < variableCount; i++) {
        if (i > 0) {
          buffer.write(", ");
        }
        (typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
      }
      buffer.write(">");
    }
    if (supertype != null && !supertype.isObject) {
      buffer.write(' extends ');
      buffer.write(supertype.displayName);
    }
    if (mixins.isNotEmpty) {
      buffer.write(' with ');
      buffer.write(mixins.map((t) => t.displayName).join(', '));
    }
    if (interfaces.isNotEmpty) {
      buffer.write(' implements ');
      buffer.write(interfaces.map((t) => t.displayName).join(', '));
    }
  }

  @override
  ElementImpl getChild(String identifier) {
    ElementImpl child = super.getChild(identifier);
    if (child != null) {
      return child;
    }
    //
    // The casts in this method are safe because the set methods would have
    // thrown a CCE if any of the elements in the arrays were not of the
    // expected types.
    //
    for (ConstructorElement constructor in constructors) {
      ConstructorElementImpl constructorImpl = constructor;
      if (constructorImpl.identifier == identifier) {
        return constructorImpl;
      }
    }
    for (MethodElement method in methods) {
      MethodElementImpl methodImpl = method;
      if (methodImpl.identifier == identifier) {
        return methodImpl;
      }
    }
    for (TypeParameterElement typeParameter in typeParameters) {
      TypeParameterElementImpl typeParameterImpl = typeParameter;
      if (typeParameterImpl.identifier == identifier) {
        return typeParameterImpl;
      }
    }
    return null;
  }

  @override
  ConstructorElement getNamedConstructor(String name) =>
      getNamedConstructorFromList(name, constructors);

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    safelyVisitChildren(constructors, visitor);
    safelyVisitChildren(methods, visitor);
    safelyVisitChildren(typeParameters, visitor);
  }

  /// Compute a list of constructors for this class, which is a mixin
  /// application.  If specified, [visitedClasses] is a list of the other mixin
  /// application classes which have been visited on the way to reaching this
  /// one (this is used to detect circularities).
  List<ConstructorElement> _computeMixinAppConstructors(
      [List<ClassElementImpl> visitedClasses = null]) {
    // First get the list of constructors of the superclass which need to be
    // forwarded to this class.
    Iterable<ConstructorElement> constructorsToForward;
    if (supertype == null) {
      // Shouldn't ever happen, since the only classes with no supertype are
      // Object and mixins, and they aren't a mixin application. But for
      // safety's sake just assume an empty list.
      assert(false);
      constructorsToForward = <ConstructorElement>[];
    } else if (!supertype.element.isMixinApplication) {
      var library = this.library;
      constructorsToForward = supertype.element.constructors
          .where((constructor) => constructor.isAccessibleIn(library));
    } else {
      if (visitedClasses == null) {
        visitedClasses = <ClassElementImpl>[this];
      } else {
        if (visitedClasses.contains(this)) {
          // Loop in the class hierarchy.  Don't try to forward any
          // constructors.
          return <ConstructorElement>[];
        }
        visitedClasses.add(this);
      }
      try {
        ClassElementImpl superElement =
            AbstractClassElementImpl.getImpl(supertype.element)
                as ClassElementImpl;
        constructorsToForward =
            superElement._computeMixinAppConstructors(visitedClasses);
      } finally {
        visitedClasses.removeLast();
      }
    }

    // Figure out the type parameter substitution we need to perform in order
    // to produce constructors for this class.  We want to be robust in the
    // face of errors, so drop any extra type arguments and fill in any missing
    // ones with `dynamic`.
    List<DartType> parameterTypes =
        TypeParameterTypeImpl.getTypes(supertype.typeParameters);
    List<DartType> argumentTypes = new List<DartType>.filled(
        parameterTypes.length, DynamicTypeImpl.instance);
    for (int i = 0; i < supertype.typeArguments.length; i++) {
      if (i >= argumentTypes.length) {
        break;
      }
      argumentTypes[i] = supertype.typeArguments[i];
    }

    // Now create an implicit constructor for every constructor found above,
    // substituting type parameters as appropriate.
    return constructorsToForward
        .map((ConstructorElement superclassConstructor) {
      ConstructorElementImpl implicitConstructor =
          new ConstructorElementImpl(superclassConstructor.name, -1);
      implicitConstructor.isSynthetic = true;
      implicitConstructor.redirectedConstructor = superclassConstructor;
      List<ParameterElement> superParameters = superclassConstructor.parameters;
      int count = superParameters.length;
      if (count > 0) {
        List<ParameterElement> implicitParameters =
            new List<ParameterElement>(count);
        for (int i = 0; i < count; i++) {
          ParameterElement superParameter = superParameters[i];
          ParameterElementImpl implicitParameter;
          if (superParameter is DefaultParameterElementImpl) {
            implicitParameter =
                new DefaultParameterElementImpl(superParameter.name, -1)
                  ..constantInitializer = superParameter.constantInitializer;
          } else {
            implicitParameter =
                new ParameterElementImpl(superParameter.name, -1);
          }
          implicitParameter.isConst = superParameter.isConst;
          implicitParameter.isFinal = superParameter.isFinal;
          // ignore: deprecated_member_use_from_same_package
          implicitParameter.parameterKind = superParameter.parameterKind;
          implicitParameter.isSynthetic = true;
          implicitParameter.type =
              superParameter.type.substitute2(argumentTypes, parameterTypes);
          implicitParameters[i] = implicitParameter;
        }
        implicitConstructor.parameters = implicitParameters;
      }
      implicitConstructor.enclosingElement = this;
      return implicitConstructor;
    }).toList(growable: false);
  }

  void _createPropertiesAndAccessors() {
    assert(_accessors == null);
    assert(_fields == null);

    var context = enclosingUnit.linkedContext;
    var accessorList = <PropertyAccessorElementImpl>[];
    var fieldList = <FieldElementImpl>[];

    var fields = context.classFields(linkedNode);
    for (var field in fields) {
      var name = context.getVariableName(field);
      var fieldElement = FieldElementImpl.forLinkedNodeFactory(
        this,
        reference.getChild('@field').getChild(name),
        field,
      );
      fieldList.add(fieldElement);

      accessorList.add(fieldElement.getter);
      if (fieldElement.setter != null) {
        accessorList.add(fieldElement.setter);
      }
    }

    for (var node in linkedNode.classOrMixinDeclaration_members) {
      if (node.kind == LinkedNodeKind.methodDeclaration) {
        var isGetter = context.isGetterMethod(node);
        var isSetter = context.isSetterMethod(node);
        if (!isGetter && !isSetter) continue;

        var name = context.getMethodName(node);
        var containerRef = isGetter
            ? reference.getChild('@getter')
            : reference.getChild('@setter');

        var accessorElement = PropertyAccessorElementImpl.forLinkedNode(
          this,
          containerRef.getChild(name),
          node,
        );
        accessorList.add(accessorElement);

        var fieldRef = reference.getChild('@field').getChild(name);
        FieldElementImpl field = fieldRef.element;
        if (field == null) {
          field = new FieldElementImpl(name, -1);
          fieldRef.element = field;
          field.enclosingElement = this;
          field.isSynthetic = true;
          field.isFinal = isGetter;
          field.isStatic = accessorElement.isStatic;
          fieldList.add(field);
        } else {
          field.isFinal = false;
        }

        accessorElement.variable = field;
        if (isGetter) {
          field.getter = accessorElement;
        } else {
          field.setter = accessorElement;
        }
      }
    }

    _accessors = accessorList;
    _fields = fieldList;
  }

  /// Return `true` if the given [type] is an [InterfaceType] that can be used
  /// as a class.
  bool _isInterfaceTypeClass(DartType type) {
    if (type is InterfaceType) {
      var element = type.element;
      return !element.isEnum && !element.isMixin;
    }
    return false;
  }

  /// Return `true` if the given [type] is an [InterfaceType] that can be used
  /// as an interface or a mixin.
  bool _isInterfaceTypeInterface(DartType type) {
    return type is InterfaceType && !type.element.isEnum;
  }

  /// Resynthesize explicit fields and property accessors and fill [_fields] and
  /// [_accessors] with explicit and implicit elements.
  void _resynthesizeFieldsAndPropertyAccessors() {
    assert(_fields == null);
    assert(_accessors == null);

    var unlinkedFields = _unlinkedClass.fields;
    var unlinkedExecutables = _unlinkedClass.executables;

    // Build explicit fields and implicit property accessors.
    List<FieldElement> explicitFields;
    List<PropertyAccessorElement> implicitAccessors;
    var unlinkedFieldsLength = unlinkedFields.length;
    if (unlinkedFieldsLength != 0) {
      explicitFields = new List<FieldElement>(unlinkedFieldsLength);
      implicitAccessors = <PropertyAccessorElement>[];
      for (var i = 0; i < unlinkedFieldsLength; i++) {
        var v = unlinkedFields[i];
        FieldElementImpl field =
            new FieldElementImpl.forSerializedFactory(v, this);
        explicitFields[i] = field;
        implicitAccessors.add(
            new PropertyAccessorElementImpl_ImplicitGetter(field)
              ..enclosingElement = this);
        if (!field.isConst && !field.isFinal) {
          implicitAccessors.add(
              new PropertyAccessorElementImpl_ImplicitSetter(field)
                ..enclosingElement = this);
        }
      }
    } else {
      explicitFields = const <FieldElement>[];
      implicitAccessors = const <PropertyAccessorElement>[];
    }

    var unlinkedExecutablesLength = unlinkedExecutables.length;
    var getterSetterCount = 0;
    for (var i = 0; i < unlinkedExecutablesLength; i++) {
      var e = unlinkedExecutables[i];
      if (e.kind == UnlinkedExecutableKind.getter ||
          e.kind == UnlinkedExecutableKind.setter) {
        getterSetterCount++;
      }
    }

    // Build explicit property accessors and implicit fields.
    List<PropertyAccessorElement> explicitAccessors;
    Map<String, FieldElementImpl> implicitFields;
    if (getterSetterCount != 0) {
      explicitAccessors = new List<PropertyAccessorElement>(getterSetterCount);
      implicitFields = <String, FieldElementImpl>{};
      var index = 0;
      for (var i = 0; i < unlinkedExecutablesLength; i++) {
        var e = unlinkedExecutables[i];
        if (e.kind == UnlinkedExecutableKind.getter ||
            e.kind == UnlinkedExecutableKind.setter) {
          PropertyAccessorElementImpl accessor =
              new PropertyAccessorElementImpl.forSerialized(e, this);
          explicitAccessors[index++] = accessor;
          // Create or update the implicit field.
          String fieldName = accessor.displayName;
          FieldElementImpl field = implicitFields[fieldName];
          if (field == null) {
            field = new FieldElementImpl(fieldName, -1);
            implicitFields[fieldName] = field;
            field.enclosingElement = this;
            field.isSynthetic = true;
            field.isFinal = e.kind == UnlinkedExecutableKind.getter;
            field.isStatic = e.isStatic;
          } else {
            field.isFinal = false;
          }
          accessor.variable = field;
          if (e.kind == UnlinkedExecutableKind.getter) {
            field.getter = accessor;
          } else {
            field.setter = accessor;
          }
        }
      }
    } else {
      explicitAccessors = const <PropertyAccessorElement>[];
      implicitFields = const <String, FieldElementImpl>{};
    }

    // Combine explicit and implicit fields and property accessors.
    if (implicitFields.isEmpty) {
      _fields = explicitFields;
    } else if (explicitFields.isEmpty) {
      _fields = implicitFields.values.toList(growable: false);
    } else {
      _fields = <FieldElement>[]
        ..addAll(explicitFields)
        ..addAll(implicitFields.values);
    }
    if (explicitAccessors.isEmpty) {
      _accessors = implicitAccessors;
    } else if (implicitAccessors.isEmpty) {
      _accessors = explicitAccessors;
    } else {
      _accessors = <PropertyAccessorElement>[]
        ..addAll(explicitAccessors)
        ..addAll(implicitAccessors);
    }
  }

  bool _safeIsOrInheritsProxy(
      ClassElement element, HashSet<ClassElement> visited) {
    if (visited.contains(element)) {
      return false;
    }
    visited.add(element);
    if (element.isProxy) {
      return true;
    } else if (element.supertype != null &&
        _safeIsOrInheritsProxy(element.supertype.element, visited)) {
      return true;
    }
    List<InterfaceType> supertypes = element.interfaces;
    for (int i = 0; i < supertypes.length; i++) {
      if (_safeIsOrInheritsProxy(supertypes[i].element, visited)) {
        return true;
      }
    }
    supertypes = element.mixins;
    for (int i = 0; i < supertypes.length; i++) {
      if (_safeIsOrInheritsProxy(supertypes[i].element, visited)) {
        return true;
      }
    }
    return false;
  }

  static void collectAllSupertypes(List<InterfaceType> supertypes,
      InterfaceType startingType, InterfaceType excludeType) {
    List<InterfaceType> typesToVisit = new List<InterfaceType>();
    List<ClassElement> visitedClasses = new List<ClassElement>();
    typesToVisit.add(startingType);
    while (!typesToVisit.isEmpty) {
      InterfaceType currentType = typesToVisit.removeAt(0);
      ClassElement currentElement = currentType.element;
      if (!visitedClasses.contains(currentElement)) {
        visitedClasses.add(currentElement);
        if (!identical(currentType, excludeType)) {
          supertypes.add(currentType);
        }
        InterfaceType supertype = currentType.superclass;
        if (supertype != null) {
          typesToVisit.add(supertype);
        }
        for (InterfaceType type in currentType.superclassConstraints) {
          typesToVisit.add(type);
        }
        for (InterfaceType type in currentType.interfaces) {
          typesToVisit.add(type);
        }
        for (InterfaceType type in currentType.mixins) {
          typesToVisit.add(type);
        }
      }
    }
  }

  static ConstructorElement getNamedConstructorFromList(
      String name, List<ConstructorElement> constructors) {
    for (ConstructorElement element in constructors) {
      String elementName = element.name;
      if (elementName != null && elementName == name) {
        return element;
      }
    }
    return null;
  }
}

/// A concrete implementation of a [CompilationUnitElement].
class CompilationUnitElementImpl extends UriReferencedElementImpl
    implements CompilationUnitElement {
  /// The context in which this unit is resynthesized, or `null` if the
  /// element is not resynthesized a summary.
  final ResynthesizerContext resynthesizerContext;

  /// The unlinked representation of the unit in the summary.
  final UnlinkedUnit _unlinkedUnit;

  /// The unlinked representation of the part in the summary.
  final UnlinkedPart _unlinkedPart;

  final LinkedUnitContext linkedContext;

  /// The source that corresponds to this compilation unit.
  @override
  Source source;

  @override
  LineInfo lineInfo;

  /// The source of the library containing this compilation unit.
  ///
  /// This is the same as the source of the containing [LibraryElement],
  /// except that it does not require the containing [LibraryElement] to be
  /// computed.
  Source librarySource;

  /// A table mapping the offset of a directive to the annotations associated
  /// with that directive, or `null` if none of the annotations in the
  /// compilation unit have annotations.
  Map<int, List<ElementAnnotation>> annotationMap = null;

  /// A list containing all of the top-level accessors (getters and setters)
  /// contained in this compilation unit.
  List<PropertyAccessorElement> _accessors;

  /// A list containing all of the enums contained in this compilation unit.
  List<ClassElement> _enums;

  /// A list containing all of the top-level functions contained in this
  /// compilation unit.
  List<FunctionElement> _functions;

  /// A list containing all of the mixins contained in this compilation unit.
  List<ClassElement> _mixins;

  /// A list containing all of the function type aliases contained in this
  /// compilation unit.
  List<FunctionTypeAliasElement> _typeAliases;

  /// A list containing all of the classes contained in this compilation unit.
  List<ClassElement> _types;

  /// A list containing all of the variables contained in this compilation unit.
  List<TopLevelVariableElement> _variables;

  /// Resynthesized explicit top-level property accessors.
  UnitExplicitTopLevelAccessors _explicitTopLevelAccessors;

  /// Resynthesized explicit top-level variables.
  UnitExplicitTopLevelVariables _explicitTopLevelVariables;

  /// Description of top-level variable replacements that should be applied
  /// to implicit top-level variables because of re-linking top-level property
  /// accessors between different unit of the same library.
  Map<TopLevelVariableElement, TopLevelVariableElement>
      _topLevelVariableReplaceMap;

  /// Initialize a newly created compilation unit element to have the given
  /// [name].
  CompilationUnitElementImpl()
      : resynthesizerContext = null,
        _unlinkedUnit = null,
        _unlinkedPart = null,
        linkedContext = null,
        super(null, -1);

  CompilationUnitElementImpl.forLinkedNode(LibraryElementImpl enclosingLibrary,
      this.linkedContext, Reference reference, LinkedNode linkedNode)
      : resynthesizerContext = null,
        _unlinkedUnit = null,
        _unlinkedPart = null,
        super.forLinkedNode(enclosingLibrary, reference, linkedNode);

  /// Initialize using the given serialized information.
  CompilationUnitElementImpl.forSerialized(LibraryElementImpl enclosingLibrary,
      this.resynthesizerContext, this._unlinkedUnit, this._unlinkedPart)
      : linkedContext = null,
        super.forSerialized(null) {
    _enclosingElement = enclosingLibrary;
    _nameOffset = -1;
  }

  @override
  List<PropertyAccessorElement> get accessors {
    if (linkedNode != null) {
      if (_accessors != null) return _accessors;
      _createPropertiesAndAccessors(this);
      assert(_accessors != null);
      return _accessors;
    }
    if (_accessors == null) {
      if (_unlinkedUnit != null) {
        _explicitTopLevelAccessors ??=
            resynthesizerContext.buildTopLevelAccessors();
        _explicitTopLevelVariables ??=
            resynthesizerContext.buildTopLevelVariables();
      }
      if (_explicitTopLevelAccessors != null) {
        _accessors = <PropertyAccessorElementImpl>[]
          ..addAll(_explicitTopLevelAccessors.accessors)
          ..addAll(_explicitTopLevelVariables.implicitAccessors);
      }
    }
    return _accessors ?? const <PropertyAccessorElement>[];
  }

  /// Set the top-level accessors (getters and setters) contained in this
  /// compilation unit to the given [accessors].
  void set accessors(List<PropertyAccessorElement> accessors) {
    for (PropertyAccessorElement accessor in accessors) {
      (accessor as PropertyAccessorElementImpl).enclosingElement = this;
    }
    this._accessors = accessors;
  }

  @override
  int get codeLength {
    if (_unlinkedUnit != null) {
      return _unlinkedUnit.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (_unlinkedUnit != null) {
      return _unlinkedUnit.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  LibraryElement get enclosingElement =>
      super.enclosingElement as LibraryElement;

  @override
  CompilationUnitElementImpl get enclosingUnit {
    return this;
  }

  @override
  List<ClassElement> get enums {
    if (linkedNode != null) {
      if (_enums != null) return _enums;
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@enum');
      _enums = linkedNode.compilationUnit_declarations
          .where((node) => node.kind == LinkedNodeKind.enumDeclaration)
          .map((node) {
        var name = context.getUnitMemberName(node);
        var reference = containerRef.getChild(name);
        reference.node = node;
        return EnumElementImpl.forLinkedNode(this, reference, node);
      }).toList();
    }
    if (_unlinkedUnit != null) {
      _enums ??= _unlinkedUnit.enums
          .map((e) => new EnumElementImpl.forSerialized(e, this))
          .toList(growable: false);
    }
    return _enums ?? const <ClassElement>[];
  }

  /// Set the enums contained in this compilation unit to the given [enums].
  void set enums(List<ClassElement> enums) {
    _assertNotResynthesized(_unlinkedUnit);
    for (ClassElement enumDeclaration in enums) {
      (enumDeclaration as EnumElementImpl).enclosingElement = this;
    }
    this._enums = enums;
  }

  @override
  List<FunctionElement> get functions {
    if (_functions != null) return _functions;

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@function');
      _functions = linkedNode.compilationUnit_declarations
          .where((node) =>
              node.kind == LinkedNodeKind.functionDeclaration &&
              !context.isGetterFunction(node) &&
              !context.isSetterFunction(node))
          .map((node) {
        var name = context.getUnitMemberName(node);
        var reference = containerRef.getChild(name);
        return FunctionElementImpl.forLinkedNode(this, reference, node);
      }).toList();
    } else if (_unlinkedUnit != null) {
      _functions = _unlinkedUnit.executables
          .where((e) => e.kind == UnlinkedExecutableKind.functionOrMethod)
          .map((e) => new FunctionElementImpl.forSerialized(e, this))
          .toList(growable: false);
    }
    return _functions ?? const <FunctionElement>[];
  }

  /// Set the top-level functions contained in this compilation unit to the
  ///  given[functions].
  void set functions(List<FunctionElement> functions) {
    for (FunctionElement function in functions) {
      (function as FunctionElementImpl).enclosingElement = this;
    }
    this._functions = functions;
  }

  @override
  List<FunctionTypeAliasElement> get functionTypeAliases {
    if (_typeAliases != null) return _typeAliases;

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@typeAlias');
      _typeAliases = linkedNode.compilationUnit_declarations
          .where((node) =>
              node.kind == LinkedNodeKind.functionTypeAlias ||
              node.kind == LinkedNodeKind.genericTypeAlias)
          .map((node) {
        var name = context.getUnitMemberName(node);
        var reference = containerRef.getChild(name);
        return GenericTypeAliasElementImpl.forLinkedNode(this, reference, node);
      }).toList();
    }

    if (_unlinkedUnit != null) {
      _typeAliases = _unlinkedUnit.typedefs.map((t) {
        return new GenericTypeAliasElementImpl.forSerialized(t, this);
      }).toList(growable: false);
    }
    return _typeAliases ?? const <FunctionTypeAliasElement>[];
  }

  @override
  int get hashCode => source.hashCode;

  @override
  bool get hasLoadLibraryFunction {
    List<FunctionElement> functions = this.functions;
    for (int i = 0; i < functions.length; i++) {
      if (functions[i].name == FunctionElement.LOAD_LIBRARY_NAME) {
        return true;
      }
    }
    return false;
  }

  @override
  String get identifier => source.encoding;

  @override
  ElementKind get kind => ElementKind.COMPILATION_UNIT;

  @override
  List<ElementAnnotation> get metadata {
    if (_metadata == null) {
      if (_unlinkedPart != null) {
        return _metadata = _buildAnnotations(
            library.definingCompilationUnit as CompilationUnitElementImpl,
            _unlinkedPart.annotations);
      }
    }
    return super.metadata;
  }

  @override
  List<ClassElement> get mixins {
    if (_unlinkedUnit != null) {
      _mixins ??= _unlinkedUnit.mixins
          .map((c) => new MixinElementImpl.forSerialized(c, this))
          .toList(growable: false);
    }
    return _mixins ?? const <ClassElement>[];
  }

  /// Set the mixins contained in this compilation unit to the given [mixins].
  void set mixins(List<ClassElement> mixins) {
    _assertNotResynthesized(_unlinkedUnit);
    for (MixinElementImpl type in mixins) {
      type.enclosingElement = this;
    }
    this._mixins = mixins;
  }

  @override
  List<TopLevelVariableElement> get topLevelVariables {
    if (linkedNode != null) {
      if (_variables != null) return _variables;
      _createPropertiesAndAccessors(this);
      assert(_variables != null);
      return _variables;
    }
    if (_variables == null) {
      if (_unlinkedUnit != null) {
        _explicitTopLevelAccessors ??=
            resynthesizerContext.buildTopLevelAccessors();
        _explicitTopLevelVariables ??=
            resynthesizerContext.buildTopLevelVariables();
      }
      if (_explicitTopLevelVariables != null) {
        var variables = <TopLevelVariableElement>[]
          ..addAll(_explicitTopLevelVariables.variables)
          ..addAll(_explicitTopLevelAccessors.implicitVariables);

        // Ensure that getters and setters in different units use
        // the same top-level variables.
        BuildLibraryElementUtils.patchTopLevelAccessors(library);

        // Apply recorded patches to variables.
        _topLevelVariableReplaceMap?.forEach((from, to) {
          int index = variables.indexOf(from);
          variables[index] = to;
        });
        _topLevelVariableReplaceMap = null;

        _variables = variables;
      }
    }
    return _variables ?? const <TopLevelVariableElement>[];
  }

  /// Set the top-level variables contained in this compilation unit to the
  ///  given[variables].
  void set topLevelVariables(List<TopLevelVariableElement> variables) {
    assert(!isResynthesized);
    for (TopLevelVariableElement field in variables) {
      (field as TopLevelVariableElementImpl).enclosingElement = this;
    }
    this._variables = variables;
  }

  /// Set the function type aliases contained in this compilation unit to the
  /// given [typeAliases].
  void set typeAliases(List<FunctionTypeAliasElement> typeAliases) {
    _assertNotResynthesized(_unlinkedUnit);
    for (FunctionTypeAliasElement typeAlias in typeAliases) {
      (typeAlias as ElementImpl).enclosingElement = this;
    }
    this._typeAliases = typeAliases;
  }

  @override
  TypeParameterizedElementMixin get typeParameterContext => null;

  @override
  List<ClassElement> get types {
    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@class');
      _types = linkedNode.compilationUnit_declarations
          .where((node) =>
              node.kind == LinkedNodeKind.classDeclaration ||
              node.kind == LinkedNodeKind.classTypeAlias)
          .map((node) {
        var name = context.getUnitMemberName(node);
        var reference = containerRef.getChild(name);
        reference.node = node;
        return ClassElementImpl.forLinkedNode(this, reference, node);
      }).toList();
    } else if (_unlinkedUnit != null) {
      _types ??= _unlinkedUnit.classes
          .map((c) => new ClassElementImpl.forSerialized(c, this))
          .toList(growable: false);
    }
    return _types ?? const <ClassElement>[];
  }

  /// Set the types contained in this compilation unit to the given [types].
  void set types(List<ClassElement> types) {
    _assertNotResynthesized(_unlinkedUnit);
    for (ClassElement type in types) {
      // Another implementation of ClassElement is _DeferredClassElement,
      // which is used to resynthesize classes lazily. We cannot cast it
      // to ClassElementImpl, and it already can provide correct values of the
      // 'enclosingElement' property.
      if (type is ClassElementImpl) {
        type.enclosingElement = this;
      }
    }
    this._types = types;
  }

  @override
  bool operator ==(Object object) =>
      object is CompilationUnitElementImpl && source == object.source;

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitCompilationUnitElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    if (source == null) {
      buffer.write("{compilation unit}");
    } else {
      buffer.write(source.fullName);
    }
  }

  @deprecated
  @override
  CompilationUnit computeNode() => unit;

  /// Return the annotations associated with the directive at the given
  /// [offset], or an empty list if the directive has no annotations or if
  /// there is no directive at the given offset.
  List<ElementAnnotation> getAnnotations(int offset) {
    if (annotationMap == null) {
      return const <ElementAnnotation>[];
    }
    return annotationMap[offset] ?? const <ElementAnnotation>[];
  }

  @override
  ElementImpl getChild(String identifier) {
    //
    // The casts in this method are safe because the set methods would have
    // thrown a CCE if any of the elements in the arrays were not of the
    // expected types.
    //
    for (PropertyAccessorElement accessor in accessors) {
      PropertyAccessorElementImpl accessorImpl = accessor;
      if (accessorImpl.identifier == identifier) {
        return accessorImpl;
      }
    }
    for (TopLevelVariableElement variable in topLevelVariables) {
      TopLevelVariableElementImpl variableImpl = variable;
      if (variableImpl.identifier == identifier) {
        return variableImpl;
      }
    }
    for (FunctionElement function in functions) {
      FunctionElementImpl functionImpl = function;
      if (functionImpl.identifier == identifier) {
        return functionImpl;
      }
    }
    for (GenericTypeAliasElementImpl typeAlias in functionTypeAliases) {
      if (typeAlias.identifier == identifier) {
        return typeAlias;
      }
    }
    for (ClassElement type in types) {
      ClassElementImpl typeImpl = type;
      if (typeImpl.name == identifier) {
        return typeImpl;
      }
    }
    for (ClassElement type in enums) {
      EnumElementImpl typeImpl = type;
      if (typeImpl.identifier == identifier) {
        return typeImpl;
      }
    }
    return null;
  }

  @override
  ClassElement getEnum(String enumName) {
    for (ClassElement enumDeclaration in enums) {
      if (enumDeclaration.name == enumName) {
        return enumDeclaration;
      }
    }
    return null;
  }

  @override
  ClassElement getType(String className) {
    return getTypeFromTypes(className, types);
  }

  /// Replace the given [from] top-level variable with [to] in this compilation
  /// unit.
  void replaceTopLevelVariable(
      TopLevelVariableElement from, TopLevelVariableElement to) {
    if (_unlinkedUnit != null) {
      // Getters and setter in different units should be patched to use the
      // same variables before these variables were asked and returned.
      assert(_variables == null);
      _topLevelVariableReplaceMap ??=
          <TopLevelVariableElement, TopLevelVariableElement>{};
      _topLevelVariableReplaceMap[from] = to;
    } else {
      int index = _variables.indexOf(from);
      _variables[index] = to;
    }
  }

  /// Set the annotations associated with the directive at the given [offset] to
  /// the given list of [annotations].
  void setAnnotations(int offset, List<ElementAnnotation> annotations) {
    annotationMap ??= new HashMap<int, List<ElementAnnotation>>();
    annotationMap[offset] = annotations;
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    safelyVisitChildren(accessors, visitor);
    safelyVisitChildren(enums, visitor);
    safelyVisitChildren(functions, visitor);
    safelyVisitChildren(functionTypeAliases, visitor);
    safelyVisitChildren(mixins, visitor);
    safelyVisitChildren(types, visitor);
    safelyVisitChildren(topLevelVariables, visitor);
  }

  static ClassElement getTypeFromTypes(
      String className, List<ClassElement> types) {
    for (ClassElement type in types) {
      if (type.name == className) {
        return type;
      }
    }
    return null;
  }

  static void _createPropertiesAndAccessors(CompilationUnitElementImpl unit) {
    if (unit._variables != null) return;
    assert(unit._accessors == null);

    var accessorMap =
        <CompilationUnitElementImpl, List<PropertyAccessorElementImpl>>{};
    var variableMap =
        <CompilationUnitElementImpl, List<TopLevelVariableElementImpl>>{};

    var units = unit.library.units;
    for (CompilationUnitElementImpl unit in units) {
      var context = unit.linkedContext;

      var accessorList = <PropertyAccessorElementImpl>[];
      accessorMap[unit] = accessorList;

      var variableList = <TopLevelVariableElementImpl>[];
      variableMap[unit] = variableList;

      var variables = context.topLevelVariables(unit.linkedNode);
      for (var variable in variables) {
        var name = context.getVariableName(variable);
        var reference = unit.reference.getChild('@variable').getChild(name);
        var variableElement = TopLevelVariableElementImpl.forLinkedNodeFactory(
          unit,
          reference,
          variable,
        );
        variableList.add(variableElement);

        accessorList.add(variableElement.getter);
        if (variableElement.setter != null) {
          accessorList.add(variableElement.setter);
        }
      }

      for (var node in unit.linkedNode.compilationUnit_declarations) {
        if (node.kind == LinkedNodeKind.functionDeclaration) {
          var isGetter = context.isGetterFunction(node);
          var isSetter = context.isSetterFunction(node);
          if (!isGetter && !isSetter) continue;

          var name = context.getUnitMemberName(node);
          var containerRef = isGetter
              ? unit.reference.getChild('@getter')
              : unit.reference.getChild('@setter');

          var accessorElement = PropertyAccessorElementImpl.forLinkedNode(
            unit,
            containerRef.getChild(name),
            node,
          );
          accessorList.add(accessorElement);

          var fieldRef = unit.reference.getChild('@field').getChild(name);
          TopLevelVariableElementImpl field = fieldRef.element;
          if (field == null) {
            field = new TopLevelVariableElementImpl(name, -1);
            fieldRef.element = field;
            field.enclosingElement = unit;
            field.isSynthetic = true;
            field.isFinal = isGetter;
            variableList.add(field);
          } else {
            field.isFinal = false;
          }

          accessorElement.variable = field;
          if (isGetter) {
            field.getter = accessorElement;
          } else {
            field.setter = accessorElement;
          }
        }
      }
    }

    for (CompilationUnitElementImpl unit in units) {
      unit._accessors = accessorMap[unit];
      unit._variables = variableMap[unit];
    }
  }
}

/// A [FieldElement] for a 'const' or 'final' field that has an initializer.
///
/// TODO(paulberry): we should rename this class to reflect the fact that it's
/// used for both const and final fields.  However, we shouldn't do so until
/// we've created an API for reading the values of constants; until that API is
/// available, clients are likely to read constant values by casting to
/// ConstFieldElementImpl, so it would be a breaking change to rename this
/// class.
class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement {
  /// Initialize a newly created synthetic field element to have the given
  /// [name] and [offset].
  ConstFieldElementImpl(String name, int offset) : super(name, offset);

  ConstFieldElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created field element to have the given [name].
  ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  ConstFieldElementImpl.forSerialized(
      UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedVariable, enclosingElement);
}

/// A field element representing an enum constant.
class ConstFieldElementImpl_EnumValue extends ConstFieldElementImpl_ofEnum {
  final UnlinkedEnumValue _unlinkedEnumValue;
  final int _index;

  ConstFieldElementImpl_EnumValue(
      EnumElementImpl enumElement, this._unlinkedEnumValue, this._index)
      : super(enumElement);

  ConstFieldElementImpl_EnumValue.forLinkedNode(EnumElementImpl enumElement,
      Reference reference, LinkedNode linkedNode, this._index)
      : _unlinkedEnumValue = null,
        super.forLinkedNode(enumElement, reference, linkedNode);

  @override
  Expression get constantInitializer => null;

  @override
  String get documentationComment {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getCommentText(
        linkedNode.annotatedNode_comment,
      );
    }
    if (_unlinkedEnumValue != null) {
      return _unlinkedEnumValue.documentationComment?.text;
    }
    return super.documentationComment;
  }

  @override
  EvaluationResultImpl get evaluationResult {
    if (_evaluationResult == null) {
      Map<String, DartObjectImpl> fieldMap = <String, DartObjectImpl>{
        name: new DartObjectImpl(
            context.typeProvider.intType, new IntState(_index))
      };
      DartObjectImpl value =
          new DartObjectImpl(type, new GenericState(fieldMap));
      _evaluationResult = new EvaluationResultImpl(value);
    }
    return _evaluationResult;
  }

  @override
  List<ElementAnnotation> get metadata {
    if (_unlinkedEnumValue != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, _unlinkedEnumValue.annotations);
    }
    return super.metadata;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (_unlinkedEnumValue != null) {
      return _unlinkedEnumValue.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getSimpleOffset(
        linkedNode.enumConstantDeclaration_name,
      );
    }
    int offset = super.nameOffset;
    if (offset == -1) {
      if (_unlinkedEnumValue != null) {
        return _unlinkedEnumValue.nameOffset;
      }
    }
    return offset;
  }

  @override
  InterfaceType get type => _enum.type;
}

/// The synthetic `values` field of an enum.
class ConstFieldElementImpl_EnumValues extends ConstFieldElementImpl_ofEnum {
  ConstFieldElementImpl_EnumValues(EnumElementImpl enumElement)
      : super(enumElement) {
    isSynthetic = true;
  }

  @override
  EvaluationResultImpl get evaluationResult {
    if (_evaluationResult == null) {
      List<DartObjectImpl> constantValues = <DartObjectImpl>[];
      for (FieldElement field in _enum.fields) {
        if (field is ConstFieldElementImpl_EnumValue) {
          constantValues.add(field.evaluationResult.value);
        }
      }
      _evaluationResult = new EvaluationResultImpl(
          new DartObjectImpl(type, new ListState(constantValues)));
    }
    return _evaluationResult;
  }

  @override
  String get name => 'values';

  @override
  InterfaceType get type {
    if (_type == null) {
      InterfaceType listType = context.typeProvider.listType;
      return _type = listType.instantiate(<DartType>[_enum.type]);
    }
    return _type;
  }
}

/// An abstract constant field of an enum.
abstract class ConstFieldElementImpl_ofEnum extends ConstFieldElementImpl {
  final EnumElementImpl _enum;

  ConstFieldElementImpl_ofEnum(this._enum) : super(null, -1) {
    enclosingElement = _enum;
  }

  ConstFieldElementImpl_ofEnum.forLinkedNode(
      this._enum, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(_enum, reference, linkedNode);

  @override
  void set evaluationResult(_) {
    assert(false);
  }

  @override
  bool get isConst => true;

  @override
  void set isConst(bool isConst) {
    assert(false);
  }

  @override
  bool get isConstantEvaluated => true;

  @override
  void set isFinal(bool isFinal) {
    assert(false);
  }

  @override
  bool get isStatic => true;

  @override
  void set isStatic(bool isStatic) {
    assert(false);
  }

  void set type(DartType type) {
    assert(false);
  }
}

/// A [LocalVariableElement] for a local 'const' variable that has an
/// initializer.
class ConstLocalVariableElementImpl extends LocalVariableElementImpl
    with ConstVariableElement {
  /// Initialize a newly created local variable element to have the given [name]
  /// and [offset].
  ConstLocalVariableElementImpl(String name, int offset) : super(name, offset);

  /// Initialize a newly created local variable element to have the given
  /// [name].
  ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
}

/// A concrete implementation of a [ConstructorElement].
class ConstructorElementImpl extends ExecutableElementImpl
    implements ConstructorElement {
  /// The constructor to which this constructor is redirecting.
  ConstructorElement _redirectedConstructor;

  /// The initializers for this constructor (used for evaluating constant
  /// instance creation expressions).
  List<ConstructorInitializer> _constantInitializers;

  /// The offset of the `.` before this constructor name or `null` if not named.
  int _periodOffset;

  /// Return the offset of the character immediately following the last
  /// character of this constructor's name, or `null` if not named.
  int _nameEnd;

  /// For every constructor we initially set this flag to `true`, and then
  /// set it to `false` during computing constant values if we detect that it
  /// is a part of a cycle.
  bool _isCycleFree = true;

  @override
  bool isConstantEvaluated = false;

  /// Initialize a newly created constructor element to have the given [name]
  /// and [offset].
  ConstructorElementImpl(String name, int offset) : super(name, offset);

  ConstructorElementImpl.forLinkedNode(Reference reference,
      LinkedNode linkedNode, ClassElementImpl enclosingClass)
      : super.forLinkedNode(enclosingClass, reference, linkedNode);

  /// Initialize a newly created constructor element to have the given [name].
  ConstructorElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  ConstructorElementImpl.forSerialized(
      UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
      : super.forSerialized(serializedExecutable, enclosingClass);

  /// Return the constant initializers for this element, which will be empty if
  /// there are no initializers, or `null` if there was an error in the source.
  List<ConstructorInitializer> get constantInitializers {
    if (_constantInitializers == null) {
      if (serializedExecutable != null) {
        _constantInitializers = serializedExecutable.constantInitializers
            .map((i) => _buildConstructorInitializer(i))
            .toList(growable: false);
      }
    }
    return _constantInitializers;
  }

  void set constantInitializers(
      List<ConstructorInitializer> constantInitializers) {
    _assertNotResynthesized(serializedExecutable);
    _constantInitializers = constantInitializers;
  }

  @override
  String get displayName {
    if (linkedNode != null) {
      return reference.name;
    }
    return super.displayName;
  }

  @override
  ClassElementImpl get enclosingElement =>
      super.enclosingElement as ClassElementImpl;

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext =>
      super.enclosingElement as ClassElementImpl;

  /// Set whether this constructor represents a factory method.
  void set factory(bool isFactory) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.FACTORY, isFactory);
  }

  @override
  bool get isConst {
    if (linkedNode != null) {
      return linkedNode.constructorDeclaration_constKeyword != 0;
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isConst;
    }
    return hasModifier(Modifier.CONST);
  }

  /// Set whether this constructor represents a 'const' constructor.
  void set isConst(bool isConst) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.CONST, isConst);
  }

  bool get isCycleFree {
    if (serializedExecutable != null) {
      return serializedExecutable.isConst &&
          !enclosingUnit.resynthesizerContext
              .isInConstCycle(serializedExecutable.constCycleSlot);
    }
    return _isCycleFree;
  }

  void set isCycleFree(bool isCycleFree) {
    // This property is updated in ConstantEvaluationEngine even for
    // resynthesized constructors, so we don't have the usual assert here.
    _isCycleFree = isCycleFree;
  }

  @override
  bool get isDefaultConstructor {
    // unnamed
    String name = this.name;
    if (name != null && name.length != 0) {
      return false;
    }
    // no required parameters
    for (ParameterElement parameter in parameters) {
      if (parameter.isNotOptional) {
        return false;
      }
    }
    // OK, can be used as default constructor
    return true;
  }

  @override
  bool get isFactory {
    if (linkedNode != null) {
      return linkedNode.constructorDeclaration_factoryKeyword != 0;
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isFactory;
    }
    return hasModifier(Modifier.FACTORY);
  }

  @override
  bool get isStatic => false;

  @override
  ElementKind get kind => ElementKind.CONSTRUCTOR;

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    return super.name;
  }

  @override
  int get nameEnd {
    if (serializedExecutable != null) {
      if (serializedExecutable.name.isNotEmpty) {
        return serializedExecutable.nameEnd;
      } else {
        return serializedExecutable.nameOffset + enclosingElement.name.length;
      }
    }
    return _nameEnd;
  }

  void set nameEnd(int nameEnd) {
    _assertNotResynthesized(serializedExecutable);
    _nameEnd = nameEnd;
  }

  @override
  int get periodOffset {
    if (serializedExecutable != null) {
      if (serializedExecutable.name.isNotEmpty) {
        return serializedExecutable.periodOffset;
      }
    }
    return _periodOffset;
  }

  void set periodOffset(int periodOffset) {
    _assertNotResynthesized(serializedExecutable);
    _periodOffset = periodOffset;
  }

  @override
  ConstructorElement get redirectedConstructor {
    if (_redirectedConstructor == null) {
      if (serializedExecutable != null) {
        if (serializedExecutable.isRedirectedConstructor) {
          if (serializedExecutable.isFactory) {
            _redirectedConstructor = enclosingUnit.resynthesizerContext
                .resolveConstructorRef(enclosingElement,
                    serializedExecutable.redirectedConstructor);
          } else {
            _redirectedConstructor = enclosingElement.getNamedConstructor(
                serializedExecutable.redirectedConstructorName);
          }
        } else {
          return null;
        }
      }
    }
    return _redirectedConstructor;
  }

  void set redirectedConstructor(ConstructorElement redirectedConstructor) {
    _assertNotResynthesized(serializedExecutable);
    _redirectedConstructor = redirectedConstructor;
  }

  @override
  DartType get returnType => enclosingElement.type;

  void set returnType(DartType returnType) {
    assert(false);
  }

  @override
  FunctionType get type {
    return _type ??= new FunctionTypeImpl(this);
  }

  void set type(FunctionType type) {
    assert(false);
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitConstructorElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    if (enclosingElement == null) {
      String message;
      String name = displayName;
      if (name != null && !name.isEmpty) {
        message =
            'Found constructor element named $name with no enclosing element';
      } else {
        message = 'Found unnamed constructor element with no enclosing element';
      }
      AnalysisEngine.instance.logger.logError(message);
      buffer.write('<unknown class>');
    } else {
      buffer.write(enclosingElement.displayName);
    }
    String name = displayName;
    if (name != null && !name.isEmpty) {
      buffer.write(".");
      buffer.write(name);
    }
    super.appendTo(buffer);
  }

  @deprecated
  @override
  ConstructorDeclaration computeNode() =>
      getNodeMatching((node) => node is ConstructorDeclaration);

  /// Resynthesize the AST for the given serialized constructor initializer.
  ConstructorInitializer _buildConstructorInitializer(
      UnlinkedConstructorInitializer serialized) {
    UnlinkedConstructorInitializerKind kind = serialized.kind;
    String name = serialized.name;
    List<Expression> arguments = <Expression>[];
    {
      int numArguments = serialized.arguments.length;
      int numNames = serialized.argumentNames.length;
      for (int i = 0; i < numArguments; i++) {
        Expression expression = enclosingUnit.resynthesizerContext
            .buildExpression(this, serialized.arguments[i]);
        int nameIndex = numNames + i - numArguments;
        if (nameIndex >= 0) {
          expression = AstTestFactory.namedExpression2(
              serialized.argumentNames[nameIndex], expression);
        }
        arguments.add(expression);
      }
    }
    switch (kind) {
      case UnlinkedConstructorInitializerKind.field:
        ConstructorFieldInitializer initializer =
            AstTestFactory.constructorFieldInitializer(
                false,
                name,
                enclosingUnit.resynthesizerContext
                    .buildExpression(this, serialized.expression));
        initializer.fieldName.staticElement = enclosingElement.getField(name);
        return initializer;
      case UnlinkedConstructorInitializerKind.assertInvocation:
        return AstTestFactory.assertInitializer(
            arguments[0], arguments.length > 1 ? arguments[1] : null);
      case UnlinkedConstructorInitializerKind.superInvocation:
        SuperConstructorInvocation initializer =
            AstTestFactory.superConstructorInvocation2(
                name.isNotEmpty ? name : null, arguments);
        ClassElement superElement = enclosingElement.supertype.element;
        ConstructorElement element = name.isEmpty
            ? superElement.unnamedConstructor
            : superElement.getNamedConstructor(name);
        initializer.staticElement = element;
        initializer.constructorName?.staticElement = element;
        return initializer;
      case UnlinkedConstructorInitializerKind.thisInvocation:
        RedirectingConstructorInvocation initializer =
            AstTestFactory.redirectingConstructorInvocation2(
                name.isNotEmpty ? name : null, arguments);
        ConstructorElement element = name.isEmpty
            ? enclosingElement.unnamedConstructor
            : enclosingElement.getNamedConstructor(name);
        initializer.staticElement = element;
        initializer.constructorName?.staticElement = element;
        return initializer;
    }
    return null;
  }
}

/// A [TopLevelVariableElement] for a top-level 'const' variable that has an
/// initializer.
class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl
    with ConstVariableElement {
  /// Initialize a newly created synthetic top-level variable element to have
  /// the given [name] and [offset].
  ConstTopLevelVariableElementImpl(String name, int offset)
      : super(name, offset);

  ConstTopLevelVariableElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created top-level variable element to have the given
  /// [name].
  ConstTopLevelVariableElementImpl.forNode(Identifier name)
      : super.forNode(name);

  /// Initialize using the given serialized information.
  ConstTopLevelVariableElementImpl.forSerialized(
      UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedVariable, enclosingElement);
}

/// Mixin used by elements that represent constant variables and have
/// initializers.
///
/// Note that in correct Dart code, all constant variables must have
/// initializers.  However, analyzer also needs to handle incorrect Dart code,
/// in which case there might be some constant variables that lack initializers.
/// This interface is only used for constant variables that have initializers.
///
/// This class is not intended to be part of the public API for analyzer.
mixin ConstVariableElement implements ElementImpl, ConstantEvaluationTarget {
  /// If this element represents a constant variable, and it has an initializer,
  /// a copy of the initializer for the constant.  Otherwise `null`.
  ///
  /// Note that in correct Dart code, all constant variables must have
  /// initializers.  However, analyzer also needs to handle incorrect Dart code,
  /// in which case there might be some constant variables that lack
  /// initializers.
  Expression _constantInitializer;

  EvaluationResultImpl _evaluationResult;

  Expression get constantInitializer {
    if (_constantInitializer != null) return _constantInitializer;

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      return _constantInitializer = context.readInitializer(this, linkedNode);
    }

    if (_unlinkedConst != null) {
      _constantInitializer = enclosingUnit.resynthesizerContext
          .buildExpression(this, _unlinkedConst);
    }
    return _constantInitializer;
  }

  void set constantInitializer(Expression constantInitializer) {
    _assertNotResynthesized(_unlinkedConst);
    _constantInitializer = constantInitializer;
  }

  EvaluationResultImpl get evaluationResult => _evaluationResult;

  void set evaluationResult(EvaluationResultImpl evaluationResult) {
    _evaluationResult = evaluationResult;
  }

  @override
  bool get isConstantEvaluated => _evaluationResult != null;

  /// If this element is resynthesized from the summary, return the unlinked
  /// initializer, otherwise return `null`.
  UnlinkedExpr get _unlinkedConst;

  /// Return a representation of the value of this variable, forcing the value
  /// to be computed if it had not previously been computed, or `null` if either
  /// this variable was not declared with the 'const' modifier or if the value
  /// of this variable could not be computed because of errors.
  DartObject computeConstantValue() {
    if (evaluationResult == null) {
      AnalysisOptionsImpl analysisOptions = context.analysisOptions;
      computeConstants(context.typeProvider, context.typeSystem,
          context.declaredVariables, [this], analysisOptions.experimentStatus);
    }
    return evaluationResult?.value;
  }
}

/// A [FieldFormalParameterElementImpl] for parameters that have an initializer.
class DefaultFieldFormalParameterElementImpl
    extends FieldFormalParameterElementImpl with ConstVariableElement {
  /// Initialize a newly created parameter element to have the given [name] and
  /// [nameOffset].
  DefaultFieldFormalParameterElementImpl(String name, int nameOffset)
      : super(name, nameOffset);

  /// Initialize a newly created parameter element to have the given [name].
  DefaultFieldFormalParameterElementImpl.forNode(Identifier name)
      : super.forNode(name);

  /// Initialize using the given serialized information.
  DefaultFieldFormalParameterElementImpl.forSerialized(
      UnlinkedParam unlinkedParam, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedParam, enclosingElement);
}

/// A [ParameterElement] for parameters that have an initializer.
class DefaultParameterElementImpl extends ParameterElementImpl
    with ConstVariableElement {
  /// Initialize a newly created parameter element to have the given [name] and
  /// [nameOffset].
  DefaultParameterElementImpl(String name, int nameOffset)
      : super(name, nameOffset);

  DefaultParameterElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created parameter element to have the given [name].
  DefaultParameterElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  DefaultParameterElementImpl.forSerialized(
      UnlinkedParam unlinkedParam, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedParam, enclosingElement);

  @deprecated
  @override
  DefaultFormalParameter computeNode() =>
      getNodeMatching((node) => node is DefaultFormalParameter);
}

/// The synthetic element representing the declaration of the type `dynamic`.
class DynamicElementImpl extends ElementImpl implements TypeDefiningElement {
  /// Return the unique instance of this class.
  static DynamicElementImpl get instance =>
      DynamicTypeImpl.instance.element as DynamicElementImpl;

  @override
  DynamicTypeImpl type;

  /// Initialize a newly created instance of this class. Instances of this class
  /// should <b>not</b> be created except as part of creating the type
  /// associated with this element. The single instance of this class should be
  /// accessed through the method [instance].
  DynamicElementImpl() : super(Keyword.DYNAMIC.lexeme, -1) {
    setModifier(Modifier.SYNTHETIC, true);
  }

  @override
  ElementKind get kind => ElementKind.DYNAMIC;

  @override
  T accept<T>(ElementVisitor<T> visitor) => null;
}

/// A concrete implementation of an [ElementAnnotation].
class ElementAnnotationImpl implements ElementAnnotation {
  /// The name of the top-level variable used to mark that a function always
  /// throws, for dead code purposes.
  static String _ALWAYS_THROWS_VARIABLE_NAME = "alwaysThrows";

  /// The name of the class used to mark an element as being deprecated.
  static String _DEPRECATED_CLASS_NAME = "Deprecated";

  /// The name of the top-level variable used to mark an element as being
  /// deprecated.
  static String _DEPRECATED_VARIABLE_NAME = "deprecated";

  /// The name of the top-level variable used to mark a method as being a
  /// factory.
  static String _FACTORY_VARIABLE_NAME = "factory";

  /// The name of the top-level variable used to mark a class and its subclasses
  /// as being immutable.
  static String _IMMUTABLE_VARIABLE_NAME = "immutable";

  /// The name of the top-level variable used to mark a constructor as being
  /// literal.
  static String _LITERAL_VARIABLE_NAME = "literal";

  /// The name of the top-level variable used to mark a function as running
  /// a single test.
  static String _IS_TEST_VARIABLE_NAME = "isTest";

  /// The name of the top-level variable used to mark a function as running
  /// a test group.
  static String _IS_TEST_GROUP_VARIABLE_NAME = "isTestGroup";

  /// The name of the class used to JS annotate an element.
  static String _JS_CLASS_NAME = "JS";

  /// The name of `js` library, used to define JS annotations.
  static String _JS_LIB_NAME = "js";

  /// The name of `meta` library, used to define analysis annotations.
  static String _META_LIB_NAME = "meta";

  /// The name of the top-level variable used to mark a method as requiring
  /// overriders to call super.
  static String _MUST_CALL_SUPER_VARIABLE_NAME = "mustCallSuper";

  /// The name of `angular.meta` library, used to define angular analysis
  /// annotations.
  static String _NG_META_LIB_NAME = "angular.meta";

  /// The name of the top-level variable used to mark a method as being expected
  /// to override an inherited method.
  static String _OVERRIDE_VARIABLE_NAME = "override";

  /// The name of the top-level variable used to mark a method as being
  /// protected.
  static String _PROTECTED_VARIABLE_NAME = "protected";

  /// The name of the top-level variable used to mark a class as implementing a
  /// proxy object.
  static String PROXY_VARIABLE_NAME = "proxy";

  /// The name of the class used to mark a parameter as being required.
  static String _REQUIRED_CLASS_NAME = "Required";

  /// The name of the top-level variable used to mark a parameter as being
  /// required.
  static String _REQUIRED_VARIABLE_NAME = "required";

  /// The name of the top-level variable used to mark a class as being sealed.
  static String _SEALED_VARIABLE_NAME = "sealed";

  /// The name of the top-level variable used to mark a method as being
  /// visible for templates.
  static String _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME = "visibleForTemplate";

  /// The name of the top-level variable used to mark a method as being
  /// visible for testing.
  static String _VISIBLE_FOR_TESTING_VARIABLE_NAME = "visibleForTesting";

  /// The element representing the field, variable, or constructor being used as
  /// an annotation.
  Element element;

  /// The compilation unit in which this annotation appears.
  CompilationUnitElementImpl compilationUnit;

  /// The AST of the annotation itself, cloned from the resolved AST for the
  /// source code.
  Annotation annotationAst;

  /// The result of evaluating this annotation as a compile-time constant
  /// expression, or `null` if the compilation unit containing the variable has
  /// not been resolved.
  EvaluationResultImpl evaluationResult;

  /// Initialize a newly created annotation. The given [compilationUnit] is the
  /// compilation unit in which the annotation appears.
  ElementAnnotationImpl(this.compilationUnit);

  @override
  List<AnalysisError> get constantEvaluationErrors =>
      evaluationResult?.errors ?? const <AnalysisError>[];

  @override
  DartObject get constantValue => evaluationResult?.value;

  @override
  AnalysisContext get context => compilationUnit.library.context;

  @override
  bool get isAlwaysThrows =>
      element is PropertyAccessorElement &&
      element.name == _ALWAYS_THROWS_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isConstantEvaluated => evaluationResult != null;

  @override
  bool get isDeprecated {
    if (element?.library?.isDartCore == true) {
      if (element is ConstructorElement) {
        return element.enclosingElement.name == _DEPRECATED_CLASS_NAME;
      } else if (element is PropertyAccessorElement) {
        return element.name == _DEPRECATED_VARIABLE_NAME;
      }
    }
    return false;
  }

  @override
  bool get isFactory =>
      element is PropertyAccessorElement &&
      element.name == _FACTORY_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isImmutable =>
      element is PropertyAccessorElement &&
      element.name == _IMMUTABLE_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isIsTest =>
      element is PropertyAccessorElement &&
      element.name == _IS_TEST_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isIsTestGroup =>
      element is PropertyAccessorElement &&
      element.name == _IS_TEST_GROUP_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isJS =>
      element is ConstructorElement &&
      element.enclosingElement.name == _JS_CLASS_NAME &&
      element.library?.name == _JS_LIB_NAME;

  @override
  bool get isLiteral =>
      element is PropertyAccessorElement &&
      element.name == _LITERAL_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isMustCallSuper =>
      element is PropertyAccessorElement &&
      element.name == _MUST_CALL_SUPER_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isOverride =>
      element is PropertyAccessorElement &&
      element.name == _OVERRIDE_VARIABLE_NAME &&
      element.library?.isDartCore == true;

  @override
  bool get isProtected =>
      element is PropertyAccessorElement &&
      element.name == _PROTECTED_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isProxy =>
      element is PropertyAccessorElement &&
      element.name == PROXY_VARIABLE_NAME &&
      element.library?.isDartCore == true;

  @override
  bool get isRequired =>
      element is ConstructorElement &&
          element.enclosingElement.name == _REQUIRED_CLASS_NAME &&
          element.library?.name == _META_LIB_NAME ||
      element is PropertyAccessorElement &&
          element.name == _REQUIRED_VARIABLE_NAME &&
          element.library?.name == _META_LIB_NAME;

  @override
  bool get isSealed =>
      element is PropertyAccessorElement &&
      element.name == _SEALED_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  @override
  bool get isVisibleForTemplate =>
      element is PropertyAccessorElement &&
      element.name == _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME &&
      element.library?.name == _NG_META_LIB_NAME;

  @override
  bool get isVisibleForTesting =>
      element is PropertyAccessorElement &&
      element.name == _VISIBLE_FOR_TESTING_VARIABLE_NAME &&
      element.library?.name == _META_LIB_NAME;

  /// Get the library containing this annotation.
  Source get librarySource => compilationUnit.librarySource;

  @override
  Source get source => compilationUnit.source;

  @override
  DartObject computeConstantValue() {
    if (evaluationResult == null) {
      AnalysisOptionsImpl analysisOptions = context.analysisOptions;
      computeConstants(context.typeProvider, context.typeSystem,
          context.declaredVariables, [this], analysisOptions.experimentStatus);
    }
    return constantValue;
  }

  @override
  String toSource() => annotationAst.toSource();

  @override
  String toString() => '@$element';
}

/// A base class for concrete implementations of an [Element].
abstract class ElementImpl implements Element {
  /// An Unicode right arrow.
  static final String RIGHT_ARROW = " \u2192 ";

  static int _NEXT_ID = 0;

  final int id = _NEXT_ID++;

  /// The enclosing element of this element, or `null` if this element is at the
  /// root of the element structure.
  ElementImpl _enclosingElement;

  Reference reference;
  final LinkedNode linkedNode;

  /// The name of this element.
  String _name;

  /// The offset of the name of this element in the file that contains the
  /// declaration of this element.
  int _nameOffset = 0;

  /// A bit-encoded form of the modifiers associated with this element.
  int _modifiers = 0;

  /// A list containing all of the metadata associated with this element.
  List<ElementAnnotation> _metadata;

  /// A cached copy of the calculated hashCode for this element.
  int _cachedHashCode;

  /// A cached copy of the calculated location for this element.
  ElementLocation _cachedLocation;

  /// The documentation comment for this element.
  String _docComment;

  /// The offset of the beginning of the element's code in the file that
  /// contains the element, or `null` if the element is synthetic.
  int _codeOffset;

  /// The length of the element's code, or `null` if the element is synthetic.
  int _codeLength;

  /// Initialize a newly created element to have the given [name] at the given
  /// [_nameOffset].
  ElementImpl(String name, this._nameOffset, {this.reference})
      : linkedNode = null {
    this._name = StringUtilities.intern(name);
    this.reference?.element = this;
  }

  /// Initialize from linked node.
  ElementImpl.forLinkedNode(
      this._enclosingElement, this.reference, this.linkedNode) {
    reference?.element = this;
  }

  /// Initialize a newly created element to have the given [name].
  ElementImpl.forNode(Identifier name)
      : this(name == null ? "" : name.name, name == null ? -1 : name.offset);

  /// Initialize from serialized information.
  ElementImpl.forSerialized(this._enclosingElement)
      : reference = null,
        linkedNode = null;

  /// The length of the element's code, or `null` if the element is synthetic.
  int get codeLength => _codeLength;

  /// The offset of the beginning of the element's code in the file that
  /// contains the element, or `null` if the element is synthetic.
  int get codeOffset => _codeOffset;

  @override
  AnalysisContext get context {
    if (_enclosingElement == null) {
      return null;
    }
    return _enclosingElement.context;
  }

  @override
  String get displayName => _name;

  @override
  String get documentationComment => _docComment;

  /// The documentation comment source for this element.
  void set documentationComment(String doc) {
    assert(!isResynthesized);
    _docComment = doc?.replaceAll('\r\n', '\n');
  }

  @override
  Element get enclosingElement => _enclosingElement;

  /// Set the enclosing element of this element to the given [element].
  void set enclosingElement(Element element) {
    _enclosingElement = element as ElementImpl;
  }

  /// Return the enclosing unit element (which might be the same as `this`), or
  /// `null` if this element is not contained in any compilation unit.
  CompilationUnitElementImpl get enclosingUnit {
    return _enclosingElement?.enclosingUnit;
  }

  @override
  bool get hasAlwaysThrows {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isAlwaysThrows) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasDeprecated {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isDeprecated) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasFactory {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isFactory) {
        return true;
      }
    }
    return false;
  }

  @override
  int get hashCode {
    // TODO: We might want to re-visit this optimization in the future.
    // We cache the hash code value as this is a very frequently called method.
    if (_cachedHashCode == null) {
      _cachedHashCode = location.hashCode;
    }
    return _cachedHashCode;
  }

  @override
  bool get hasIsTest {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isIsTest) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasIsTestGroup {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isIsTestGroup) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasJS {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isJS) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasLiteral {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isLiteral) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasOverride {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isOverride) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasProtected {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isProtected) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasRequired {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isRequired) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasSealed {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isSealed) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasVisibleForTemplate {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isVisibleForTemplate) {
        return true;
      }
    }
    return false;
  }

  @override
  bool get hasVisibleForTesting {
    var metadata = this.metadata;
    for (var i = 0; i < metadata.length; i++) {
      var annotation = metadata[i];
      if (annotation.isVisibleForTesting) {
        return true;
      }
    }
    return false;
  }

  /// Return an identifier that uniquely identifies this element among the
  /// children of this element's parent.
  String get identifier => name;

  @override
  bool get isAlwaysThrows => hasAlwaysThrows;

  @override
  bool get isDeprecated => hasDeprecated;

  @override
  bool get isFactory => hasFactory;

  @override
  bool get isJS => hasJS;

  @override
  bool get isOverride => hasOverride;

  @override
  bool get isPrivate {
    String name = displayName;
    if (name == null) {
      return true;
    }
    return Identifier.isPrivateName(name);
  }

  @override
  bool get isProtected => hasProtected;

  @override
  bool get isPublic => !isPrivate;

  @override
  bool get isRequired => hasRequired;

  /// Return `true` if this element is resynthesized from a summary.
  bool get isResynthesized => enclosingUnit?.resynthesizerContext != null;

  @override
  bool get isSynthetic {
    if (linkedNode != null) {
      return linkedNode.isSynthetic;
    }
    return hasModifier(Modifier.SYNTHETIC);
  }

  /// Set whether this element is synthetic.
  void set isSynthetic(bool isSynthetic) {
    setModifier(Modifier.SYNTHETIC, isSynthetic);
  }

  @override
  bool get isVisibleForTesting => hasVisibleForTesting;

  @override
  LibraryElement get library =>
      getAncestor((element) => element is LibraryElement);

  @override
  Source get librarySource => library?.source;

  @override
  ElementLocation get location {
    if (_cachedLocation == null) {
      if (library == null) {
        return new ElementLocationImpl.con1(this);
      }
      _cachedLocation = new ElementLocationImpl.con1(this);
    }
    return _cachedLocation;
  }

  List<ElementAnnotation> get metadata {
    if (linkedNode != null) {
      if (_metadata != null) return _metadata;
      var metadata = enclosingUnit.linkedContext.getMetadataOrEmpty(linkedNode);
      return _metadata = _buildAnnotations2(enclosingUnit, metadata);
    }
    return _metadata ?? const <ElementAnnotation>[];
  }

  void set metadata(List<ElementAnnotation> metadata) {
    assert(!isResynthesized);
    _metadata = metadata;
  }

  @override
  String get name => _name;

  /// Changes the name of this element.
  void set name(String name) {
    this._name = name;
  }

  @override
  int get nameLength => displayName != null ? displayName.length : 0;

  @override
  int get nameOffset => _nameOffset;

  /// Sets the offset of the name of this element in the file that contains the
  /// declaration of this element.
  void set nameOffset(int offset) {
    _nameOffset = offset;
  }

  @override
  AnalysisSession get session {
    return _enclosingElement?.session;
  }

  @override
  Source get source {
    if (_enclosingElement == null) {
      return null;
    }
    return _enclosingElement.source;
  }

  /// Return the context to resolve type parameters in, or `null` if neither
  /// this element nor any of its ancestors is of a kind that can declare type
  /// parameters.
  TypeParameterizedElementMixin get typeParameterContext {
    return _enclosingElement?.typeParameterContext;
  }

  @deprecated
  @override
  CompilationUnit get unit => context.resolveCompilationUnit(source, library);

  @override
  bool operator ==(Object object) {
    if (identical(this, object)) {
      return true;
    }
    return object is Element &&
        object.kind == kind &&
        object.location == location;
  }

  /// Append to the given [buffer] a comma-separated list of the names of the
  /// types of this element and every enclosing element.
  void appendPathTo(StringBuffer buffer) {
    Element element = this;
    while (element != null) {
      if (element != this) {
        buffer.write(', ');
      }
      buffer.write(element.runtimeType);
      String name = element.name;
      if (name != null) {
        buffer.write(' (');
        buffer.write(name);
        buffer.write(')');
      }
      element = element.enclosingElement;
    }
  }

  /// Append a textual representation of this element to the given [buffer].
  void appendTo(StringBuffer buffer) {
    if (_name == null) {
      buffer.write("<unnamed ");
      buffer.write(runtimeType.toString());
      buffer.write(">");
    } else {
      buffer.write(_name);
    }
  }

  @override
  String computeDocumentationComment() => documentationComment;

  @deprecated
  @override
  AstNode computeNode() => getNodeMatching((node) => node is AstNode);

  /// Set this element as the enclosing element for given [element].
  void encloseElement(ElementImpl element) {
    element.enclosingElement = this;
  }

  /// Set this element as the enclosing element for given [elements].
  void encloseElements(List<Element> elements) {
    for (Element element in elements) {
      (element as ElementImpl)._enclosingElement = this;
    }
  }

  @override
  E getAncestor<E extends Element>(Predicate<Element> predicate) {
    return getAncestorStatic<E>(_enclosingElement, predicate);
  }

  /// Return the child of this element that is uniquely identified by the given
  /// [identifier], or `null` if there is no such child.
  ElementImpl getChild(String identifier) => null;

  @override
  String getExtendedDisplayName(String shortName) {
    if (shortName == null) {
      shortName = displayName;
    }
    Source source = this.source;
    if (source != null) {
      return "$shortName (${source.fullName})";
    }
    return shortName;
  }

  /// Return the resolved [AstNode] of the given type enclosing [getNameOffset].
  @deprecated
  AstNode getNodeMatching(Predicate<AstNode> predicate) {
    CompilationUnit unit = this.unit;
    if (unit == null) {
      return null;
    }
    int offset = nameOffset;
    AstNode node = new NodeLocator(offset).searchWithin(unit);
    if (node == null) {
      return null;
    }
    return node.thisOrAncestorMatching(predicate);
  }

  /// Return `true` if this element has the given [modifier] associated with it.
  bool hasModifier(Modifier modifier) =>
      BooleanArray.get(_modifiers, modifier.ordinal);

  @override
  bool isAccessibleIn(LibraryElement library) {
    if (Identifier.isPrivateName(name)) {
      return library == this.library;
    }
    return true;
  }

  /// Use the given [visitor] to visit all of the [children] in the given array.
  void safelyVisitChildren(List<Element> children, ElementVisitor visitor) {
    if (children != null) {
      for (Element child in children) {
        child.accept(visitor);
      }
    }
  }

  /// Set the code range for this element.
  void setCodeRange(int offset, int length) {
    assert(!isResynthesized);
    _codeOffset = offset;
    _codeLength = length;
  }

  /// Set whether the given [modifier] is associated with this element to
  /// correspond to the given [value].
  void setModifier(Modifier modifier, bool value) {
    _modifiers = BooleanArray.set(_modifiers, modifier.ordinal, value);
  }

  @override
  String toString() {
    StringBuffer buffer = new StringBuffer();
    appendTo(buffer);
    return buffer.toString();
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    // There are no children to visit
  }

  /// Return annotations for the given [unlinkedConsts] in the [unit].
  List<ElementAnnotation> _buildAnnotations(
      CompilationUnitElementImpl unit, List<UnlinkedExpr> unlinkedConsts) {
    int length = unlinkedConsts.length;
    if (length != 0) {
      List<ElementAnnotation> annotations = new List<ElementAnnotation>(length);
      ResynthesizerContext context = unit.resynthesizerContext;
      for (int i = 0; i < length; i++) {
        annotations[i] = context.buildAnnotation(this, unlinkedConsts[i]);
      }
      return annotations;
    } else {
      return const <ElementAnnotation>[];
    }
  }

  /// Return annotations for the given [nodeList] in the [unit].
  List<ElementAnnotation> _buildAnnotations2(
      CompilationUnitElementImpl unit, List<LinkedNode> nodeList) {
    var length = nodeList.length;
    if (length == 0) {
      return const <ElementAnnotation>[];
    }

    var annotations = new List<ElementAnnotation>(length);
    for (int i = 0; i < length; i++) {
      var ast = unit.linkedContext.readNode(nodeList[i]);
      annotations[i] = ElementAnnotationImpl(enclosingUnit)
        ..annotationAst = ast;
    }
    return annotations;
  }

  /// If the element associated with the given [type] is a generic function type
  /// element, then make it a child of this element. Return the [type] as a
  /// convenience.
  DartType _checkElementOfType(DartType type) {
    Element element = type?.element;
    if (element is GenericFunctionTypeElementImpl &&
        element.enclosingElement == null) {
      element.enclosingElement = this;
    }
    return type;
  }

  /// If the given [type] is a generic function type, then the element
  /// associated with the type is implicitly a child of this element and should
  /// be visited by the given [visitor].
  void _safelyVisitPossibleChild(DartType type, ElementVisitor visitor) {
    Element element = type?.element;
    if (element is GenericFunctionTypeElementImpl &&
        element.enclosingElement is! GenericTypeAliasElement) {
      element.accept(visitor);
    }
  }

  static int findElementIndexUsingIdentical(List items, Object item) {
    int length = items.length;
    for (int i = 0; i < length; i++) {
      if (identical(items[i], item)) {
        return i;
      }
    }
    throw new StateError('Unable to find $item in $items');
  }

  static E getAncestorStatic<E extends Element>(
      Element startingPoint, Predicate<Element> predicate) {
    Element ancestor = startingPoint;
    while (ancestor != null && !predicate(ancestor)) {
      ancestor = ancestor.enclosingElement;
    }
    return ancestor as E;
  }
}

/// A concrete implementation of an [ElementLocation].
class ElementLocationImpl implements ElementLocation {
  /// The character used to separate components in the encoded form.
  static int _SEPARATOR_CHAR = 0x3B;

  /// The path to the element whose location is represented by this object.
  List<String> _components;

  /// The object managing [indexKeyId] and [indexLocationId].
  Object indexOwner;

  /// A cached id of this location in index.
  int indexKeyId;

  /// A cached id of this location in index.
  int indexLocationId;

  /// Initialize a newly created location to represent the given [element].
  ElementLocationImpl.con1(Element element) {
    List<String> components = new List<String>();
    Element ancestor = element;
    while (ancestor != null) {
      components.insert(0, (ancestor as ElementImpl).identifier);
      ancestor = ancestor.enclosingElement;
    }
    this._components = components;
  }

  /// Initialize a newly created location from the given [encoding].
  ElementLocationImpl.con2(String encoding) {
    this._components = _decode(encoding);
  }

  /// Initialize a newly created location from the given [components].
  ElementLocationImpl.con3(List<String> components) {
    this._components = components;
  }

  @override
  List<String> get components => _components;

  @override
  String get encoding {
    StringBuffer buffer = new StringBuffer();
    int length = _components.length;
    for (int i = 0; i < length; i++) {
      if (i > 0) {
        buffer.writeCharCode(_SEPARATOR_CHAR);
      }
      _encode(buffer, _components[i]);
    }
    return buffer.toString();
  }

  @override
  int get hashCode {
    int result = 0;
    for (int i = 0; i < _components.length; i++) {
      String component = _components[i];
      result = JenkinsSmiHash.combine(result, component.hashCode);
    }
    return result;
  }

  @override
  bool operator ==(Object object) {
    if (identical(this, object)) {
      return true;
    }
    if (object is ElementLocationImpl) {
      List<String> otherComponents = object._components;
      int length = _components.length;
      if (otherComponents.length != length) {
        return false;
      }
      for (int i = 0; i < length; i++) {
        if (_components[i] != otherComponents[i]) {
          return false;
        }
      }
      return true;
    }
    return false;
  }

  @override
  String toString() => encoding;

  /// Decode the [encoding] of a location into a list of components and return
  /// the components.
  List<String> _decode(String encoding) {
    List<String> components = new List<String>();
    StringBuffer buffer = new StringBuffer();
    int index = 0;
    int length = encoding.length;
    while (index < length) {
      int currentChar = encoding.codeUnitAt(index);
      if (currentChar == _SEPARATOR_CHAR) {
        if (index + 1 < length &&
            encoding.codeUnitAt(index + 1) == _SEPARATOR_CHAR) {
          buffer.writeCharCode(_SEPARATOR_CHAR);
          index += 2;
        } else {
          components.add(buffer.toString());
          buffer = new StringBuffer();
          index++;
        }
      } else {
        buffer.writeCharCode(currentChar);
        index++;
      }
    }
    components.add(buffer.toString());
    return components;
  }

  /// Append an encoded form of the given [component] to the given [buffer].
  void _encode(StringBuffer buffer, String component) {
    int length = component.length;
    for (int i = 0; i < length; i++) {
      int currentChar = component.codeUnitAt(i);
      if (currentChar == _SEPARATOR_CHAR) {
        buffer.writeCharCode(_SEPARATOR_CHAR);
      }
      buffer.writeCharCode(currentChar);
    }
  }
}

/// An [AbstractClassElementImpl] which is an enum.
class EnumElementImpl extends AbstractClassElementImpl {
  /// The unlinked representation of the enum in the summary.
  final UnlinkedEnum _unlinkedEnum;

  /// The type defined by the enum.
  InterfaceType _type;

  /// Initialize a newly created class element to have the given [name] at the
  /// given [offset] in the file that contains the declaration of this element.
  EnumElementImpl(String name, int offset)
      : _unlinkedEnum = null,
        super(name, offset);

  EnumElementImpl.forLinkedNode(CompilationUnitElementImpl enclosing,
      Reference reference, LinkedNode linkedNode)
      : _unlinkedEnum = null,
        super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created class element to have the given [name].
  EnumElementImpl.forNode(Identifier name)
      : _unlinkedEnum = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  EnumElementImpl.forSerialized(
      this._unlinkedEnum, CompilationUnitElementImpl enclosingUnit)
      : super.forSerialized(enclosingUnit);

  /// Set whether this class is abstract.
  void set abstract(bool isAbstract) {
    _assertNotResynthesized(_unlinkedEnum);
  }

  @override
  List<PropertyAccessorElement> get accessors {
    if (_accessors == null) {
      if (linkedNode != null) {
        _resynthesizeMembers2();
      }
      if (_unlinkedEnum != null) {
        _resynthesizeMembers();
      }
    }
    return _accessors ?? const <PropertyAccessorElement>[];
  }

  @override
  void set accessors(List<PropertyAccessorElement> accessors) {
    _assertNotResynthesized(_unlinkedEnum);
    super.accessors = accessors;
  }

  @override
  List<InterfaceType> get allSupertypes => <InterfaceType>[supertype];

  @override
  int get codeLength {
    if (_unlinkedEnum != null) {
      return _unlinkedEnum.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (_unlinkedEnum != null) {
      return _unlinkedEnum.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  List<ConstructorElement> get constructors {
    // The equivalent code for enums in the spec shows a single constructor,
    // but that constructor is not callable (since it is a compile-time error
    // to subclass, mix-in, implement, or explicitly instantiate an enum).
    // So we represent this as having no constructors.
    return const <ConstructorElement>[];
  }

  @override
  String get documentationComment {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getCommentText(
        linkedNode.annotatedNode_comment,
      );
    }
    if (_unlinkedEnum != null) {
      return _unlinkedEnum.documentationComment?.text;
    }
    return super.documentationComment;
  }

  @override
  List<FieldElement> get fields {
    if (_fields == null) {
      if (linkedNode != null) {
        _resynthesizeMembers2();
      }
      if (_unlinkedEnum != null) {
        _resynthesizeMembers();
      }
    }
    return _fields ?? const <FieldElement>[];
  }

  @override
  void set fields(List<FieldElement> fields) {
    _assertNotResynthesized(_unlinkedEnum);
    super.fields = fields;
  }

  @override
  bool get hasNonFinalField => false;

  @override
  bool get hasReferenceToSuper => false;

  @override
  bool get hasStaticMember => true;

  @override
  List<InterfaceType> get interfaces => const <InterfaceType>[];

  @override
  bool get isAbstract => false;

  @override
  bool get isEnum => true;

  @override
  bool get isMixinApplication => false;

  @override
  bool get isOrInheritsProxy => false;

  @override
  bool get isProxy => false;

  @override
  bool get isSimplyBounded => true;

  @override
  bool get isValidMixin => false;

  @override
  List<ElementAnnotation> get metadata {
    if (_unlinkedEnum != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, _unlinkedEnum.annotations);
    }
    return super.metadata;
  }

  @override
  List<MethodElement> get methods {
    if (_methods == null) {
      if (linkedNode != null) {
        _resynthesizeMembers2();
      }
      if (_unlinkedEnum != null) {
        _resynthesizeMembers();
      }
    }
    return _methods ?? const <MethodElement>[];
  }

  @override
  List<InterfaceType> get mixins => const <InterfaceType>[];

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (_unlinkedEnum != null) {
      return _unlinkedEnum.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedEnum != null && _unlinkedEnum.nameOffset != 0) {
      return _unlinkedEnum.nameOffset;
    }
    return offset;
  }

  @override
  InterfaceType get supertype => context.typeProvider.objectType;

  @override
  InterfaceType get type {
    if (_type == null) {
      InterfaceTypeImpl type = new InterfaceTypeImpl(this);
      type.typeArguments = const <DartType>[];
      _type = type;
    }
    return _type;
  }

  @override
  List<TypeParameterElement> get typeParameters =>
      const <TypeParameterElement>[];

  @override
  ConstructorElement get unnamedConstructor => null;

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write('enum ');
    String name = displayName;
    if (name == null) {
      buffer.write("{unnamed enum}");
    } else {
      buffer.write(name);
    }
  }

  /// Create the only method enums have - `toString()`.
  void createToStringMethodElement() {
    var method = new MethodElementImpl('toString', -1);
    method.isSynthetic = true;
    if (linkedNode != null || _unlinkedEnum != null) {
      method.returnType = context.typeProvider.stringType;
      method.type = new FunctionTypeImpl(method);
    }
    method.enclosingElement = this;
    if (linkedNode != null) {
      method.reference = reference.getChild('@method').getChild('toString');
    }
    _methods = <MethodElement>[method];
  }

  @override
  ConstructorElement getNamedConstructor(String name) => null;

  void _resynthesizeMembers() {
    List<FieldElementImpl> fields = <FieldElementImpl>[];
    // Build the 'index' field.
    fields.add(new FieldElementImpl('index', -1)
      ..enclosingElement = this
      ..isSynthetic = true
      ..isFinal = true
      ..type = context.typeProvider.intType);
    // Build the 'values' field.
    fields.add(new ConstFieldElementImpl_EnumValues(this));
    // Build fields for all enum constants.
    if (_unlinkedEnum != null) {
      for (int i = 0; i < _unlinkedEnum.values.length; i++) {
        UnlinkedEnumValue unlinkedValue = _unlinkedEnum.values[i];
        ConstFieldElementImpl_EnumValue field =
            new ConstFieldElementImpl_EnumValue(this, unlinkedValue, i);
        fields.add(field);
      }
    }
    // done
    _fields = fields;
    _accessors = fields
        .map((FieldElementImpl field) =>
            new PropertyAccessorElementImpl_ImplicitGetter(field)
              ..enclosingElement = this)
        .toList(growable: false);
    createToStringMethodElement();
  }

  void _resynthesizeMembers2() {
    var fields = <FieldElementImpl>[];
    var getters = <PropertyAccessorElementImpl>[];

    // Build the 'index' field.
    {
      var field = FieldElementImpl('index', -1)
        ..enclosingElement = this
        ..isSynthetic = true
        ..isFinal = true
        ..type = context.typeProvider.intType;
      fields.add(field);
      getters.add(PropertyAccessorElementImpl_ImplicitGetter(field,
          reference: reference.getChild('@getter').getChild('index'))
        ..enclosingElement = this);
    }

    // Build the 'values' field.
    {
      var field = ConstFieldElementImpl_EnumValues(this);
      fields.add(field);
      getters.add(PropertyAccessorElementImpl_ImplicitGetter(field,
          reference: reference.getChild('@getter').getChild('values'))
        ..enclosingElement = this);
    }

    // Build fields for all enum constants.
    var constants = linkedNode.enumDeclaration_constants;
    for (var i = 0; i < constants.length; ++i) {
      var constant = constants[i];
      var name = enclosingUnit.linkedContext.getSimpleName(
        constant.enumConstantDeclaration_name,
      );
      var reference = this.reference.getChild('@constant').getChild(name);
      var field = new ConstFieldElementImpl_EnumValue.forLinkedNode(
          this, reference, constant, i);
      fields.add(field);
      getters.add(field.getter);
    }

    _fields = fields;
    _accessors = getters;
    createToStringMethodElement();
  }
}

/// A base class for concrete implementations of an [ExecutableElement].
abstract class ExecutableElementImpl extends ElementImpl
    with TypeParameterizedElementMixin
    implements ExecutableElement {
  /// The unlinked representation of the executable in the summary.
  final UnlinkedExecutable serializedExecutable;

  /// A list containing all of the parameters defined by this executable
  /// element.
  List<ParameterElement> _parameters;

  /// The declared return type of this executable element.
  DartType _declaredReturnType;

  /// The inferred return type of this executable element.
  DartType _returnType;

  /// The type of function defined by this executable element.
  FunctionType _type;

  /// Initialize a newly created executable element to have the given [name] and
  /// [offset].
  ExecutableElementImpl(String name, int offset, {Reference reference})
      : serializedExecutable = null,
        super(name, offset, reference: reference);

  /// Initialize using the given linked node.
  ExecutableElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : serializedExecutable = null,
        super.forLinkedNode(enclosing, reference, linkedNode) {
    reference.element = this;
  }

  /// Initialize a newly created executable element to have the given [name].
  ExecutableElementImpl.forNode(Identifier name)
      : serializedExecutable = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  ExecutableElementImpl.forSerialized(
      this.serializedExecutable, ElementImpl enclosingElement)
      : super.forSerialized(enclosingElement);

  /// Set whether this executable element's body is asynchronous.
  void set asynchronous(bool isAsynchronous) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.ASYNCHRONOUS, isAsynchronous);
  }

  @override
  int get codeLength {
    if (serializedExecutable != null) {
      return serializedExecutable.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (serializedExecutable != null) {
      return serializedExecutable.codeRange?.offset;
    }
    return super.codeOffset;
  }

  void set declaredReturnType(DartType returnType) {
    _assertNotResynthesized(serializedExecutable);
    _declaredReturnType = _checkElementOfType(returnType);
  }

  @override
  String get displayName {
    if (linkedNode != null) {
      return reference.name;
    }
    if (serializedExecutable != null) {
      return serializedExecutable.name;
    }
    return super.displayName;
  }

  @override
  String get documentationComment {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getCommentText(
        linkedNode.annotatedNode_comment,
      );
    }
    if (serializedExecutable != null) {
      return serializedExecutable.documentationComment?.text;
    }
    return super.documentationComment;
  }

  /// Set whether this executable element is external.
  void set external(bool isExternal) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.EXTERNAL, isExternal);
  }

  /// Set whether this method's body is a generator.
  void set generator(bool isGenerator) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.GENERATOR, isGenerator);
  }

  @override
  bool get hasImplicitReturnType {
    if (serializedExecutable != null) {
      return serializedExecutable.returnType == null &&
          serializedExecutable.kind != UnlinkedExecutableKind.constructor;
    }
    return hasModifier(Modifier.IMPLICIT_TYPE);
  }

  /// Set whether this executable element has an implicit return type.
  void set hasImplicitReturnType(bool hasImplicitReturnType) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.IMPLICIT_TYPE, hasImplicitReturnType);
  }

  @override
  bool get isAbstract {
    if (serializedExecutable != null) {
      return serializedExecutable.isAbstract;
    }
    return hasModifier(Modifier.ABSTRACT);
  }

  @override
  bool get isAsynchronous {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isAsynchronous(linkedNode);
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isAsynchronous;
    }
    return hasModifier(Modifier.ASYNCHRONOUS);
  }

  @override
  bool get isExternal {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isExternal(linkedNode);
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isExternal;
    }
    return hasModifier(Modifier.EXTERNAL);
  }

  @override
  bool get isGenerator {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isGenerator(linkedNode);
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isGenerator;
    }
    return hasModifier(Modifier.GENERATOR);
  }

  @override
  bool get isOperator => false;

  @override
  bool get isSynchronous => !isAsynchronous;

  @override
  List<ElementAnnotation> get metadata {
    if (serializedExecutable != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, serializedExecutable.annotations);
    }
    return super.metadata;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (serializedExecutable != null) {
      return serializedExecutable.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getSimpleOffset(
        linkedNode.namedCompilationUnitMember_name,
      );
    }

    int offset = super.nameOffset;
    if (offset == 0 && serializedExecutable != null) {
      return serializedExecutable.nameOffset;
    }
    return offset;
  }

  @override
  List<ParameterElement> get parameters {
    if (_parameters == null) {
      if (linkedNode != null) {
        var context = enclosingUnit.linkedContext;
        var containerRef = reference.getChild('@parameter');
        var formalParameters = context.getFormalParameters(linkedNode);
        _parameters = ParameterElementImpl.forLinkedNodeList(
          this,
          context,
          containerRef,
          formalParameters,
        );
      }
      if (serializedExecutable != null) {
        _parameters = ParameterElementImpl.resynthesizeList(
            serializedExecutable.parameters, this);
      }
    }
    return _parameters ?? const <ParameterElement>[];
  }

  /// Set the parameters defined by this executable element to the given
  /// [parameters].
  void set parameters(List<ParameterElement> parameters) {
    _assertNotResynthesized(serializedExecutable);
    for (ParameterElement parameter in parameters) {
      (parameter as ParameterElementImpl).enclosingElement = this;
    }
    this._parameters = parameters;
  }

  @override
  DartType get returnType {
    if (linkedNode != null) {
      return _returnType ??=
          enclosingUnit.linkedContext.getReturnType(linkedNode);
    }
    if (serializedExecutable != null &&
        _declaredReturnType == null &&
        _returnType == null) {
      bool isSetter =
          serializedExecutable.kind == UnlinkedExecutableKind.setter;
      _returnType = enclosingUnit.resynthesizerContext
          .resolveLinkedType(this, serializedExecutable.inferredReturnTypeSlot);
      _declaredReturnType = enclosingUnit.resynthesizerContext.resolveTypeRef(
          this, serializedExecutable.returnType,
          defaultVoid: isSetter, declaredType: true);
    }
    return _returnType ?? _declaredReturnType;
  }

  void set returnType(DartType returnType) {
    _assertNotResynthesized(serializedExecutable);
    _returnType = _checkElementOfType(returnType);
  }

  @override
  FunctionType get type {
    if (linkedNode != null) {
      return _type ??= new FunctionTypeImpl(this);
    }
    if (serializedExecutable != null) {
      return _type ??= new FunctionTypeImpl(this);
    }
    return _type;
  }

  void set type(FunctionType type) {
    _assertNotResynthesized(serializedExecutable);
    _type = type;
  }

  /// Set the type parameters defined by this executable element to the given
  /// [typeParameters].
  void set typeParameters(List<TypeParameterElement> typeParameters) {
    _assertNotResynthesized(serializedExecutable);
    for (TypeParameterElement parameter in typeParameters) {
      (parameter as TypeParameterElementImpl).enclosingElement = this;
    }
    this._typeParameterElements = typeParameters;
  }

  @override
  List<UnlinkedTypeParam> get unlinkedTypeParams =>
      serializedExecutable?.typeParameters;

  @override
  void appendTo(StringBuffer buffer) {
    if (this.kind != ElementKind.GETTER) {
      int typeParameterCount = typeParameters.length;
      if (typeParameterCount > 0) {
        buffer.write('<');
        for (int i = 0; i < typeParameterCount; i++) {
          if (i > 0) {
            buffer.write(", ");
          }
          (typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
        }
        buffer.write('>');
      }
      buffer.write("(");
      String closing = null;
      ParameterKind kind = ParameterKind.REQUIRED;
      int parameterCount = parameters.length;
      for (int i = 0; i < parameterCount; i++) {
        if (i > 0) {
          buffer.write(", ");
        }
        ParameterElement parameter = parameters[i];
        // ignore: deprecated_member_use_from_same_package
        ParameterKind parameterKind = parameter.parameterKind;
        if (parameterKind != kind) {
          if (closing != null) {
            buffer.write(closing);
          }
          if (parameterKind == ParameterKind.POSITIONAL) {
            buffer.write("[");
            closing = "]";
          } else if (parameterKind == ParameterKind.NAMED) {
            buffer.write("{");
            closing = "}";
          } else {
            closing = null;
          }
        }
        kind = parameterKind;
        parameter.appendToWithoutDelimiters(buffer);
      }
      if (closing != null) {
        buffer.write(closing);
      }
      buffer.write(")");
    }
    if (type != null) {
      buffer.write(ElementImpl.RIGHT_ARROW);
      buffer.write(type.returnType);
    }
  }

  @override
  ElementImpl getChild(String identifier) {
    for (ParameterElement parameter in parameters) {
      ParameterElementImpl parameterImpl = parameter;
      if (parameterImpl.identifier == identifier) {
        return parameterImpl;
      }
    }
    return null;
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    _safelyVisitPossibleChild(returnType, visitor);
    safelyVisitChildren(typeParameters, visitor);
    safelyVisitChildren(parameters, visitor);
  }
}

/// A concrete implementation of an [ExportElement].
class ExportElementImpl extends UriReferencedElementImpl
    implements ExportElement {
  /// The unlinked representation of the export in the summary.
  final UnlinkedExportPublic _unlinkedExportPublic;

  /// The unlinked representation of the export in the summary.
  final UnlinkedExportNonPublic _unlinkedExportNonPublic;

  /// The library that is exported from this library by this export directive.
  LibraryElement _exportedLibrary;

  /// The combinators that were specified as part of the export directive in the
  /// order in which they were specified.
  List<NamespaceCombinator> _combinators;

  /// The URI that was selected based on the declared variables.
  String _selectedUri;

  /// Initialize a newly created export element at the given [offset].
  ExportElementImpl(int offset)
      : _unlinkedExportPublic = null,
        _unlinkedExportNonPublic = null,
        super(null, offset);

  /// Initialize using the given serialized information.
  ExportElementImpl.forSerialized(this._unlinkedExportPublic,
      this._unlinkedExportNonPublic, LibraryElementImpl enclosingLibrary)
      : super.forSerialized(enclosingLibrary);

  @override
  List<NamespaceCombinator> get combinators {
    if (_combinators == null) {
      if (_unlinkedExportPublic != null) {
        _combinators = ImportElementImpl._buildCombinators(
            _unlinkedExportPublic.combinators);
      }
    }
    return _combinators ?? const <NamespaceCombinator>[];
  }

  void set combinators(List<NamespaceCombinator> combinators) {
    _assertNotResynthesized(_unlinkedExportPublic);
    _combinators = combinators;
  }

  @override
  LibraryElement get exportedLibrary {
    if (_exportedLibrary == null) {
      if (_unlinkedExportNonPublic != null) {
        LibraryElementImpl library = enclosingElement as LibraryElementImpl;
        _exportedLibrary =
            library.resynthesizerContext.buildExportedLibrary(uri);
      }
    }
    return _exportedLibrary;
  }

  void set exportedLibrary(LibraryElement exportedLibrary) {
    _assertNotResynthesized(_unlinkedExportNonPublic);
    _exportedLibrary = exportedLibrary;
  }

  @override
  String get identifier => exportedLibrary.name;

  @override
  ElementKind get kind => ElementKind.EXPORT;

  @override
  List<ElementAnnotation> get metadata {
    if (_metadata == null) {
      if (_unlinkedExportNonPublic != null) {
        return _metadata = _buildAnnotations(library.definingCompilationUnit,
            _unlinkedExportNonPublic.annotations);
      }
    }
    return super.metadata;
  }

  void set metadata(List<ElementAnnotation> metadata) {
    _assertNotResynthesized(_unlinkedExportNonPublic);
    super.metadata = metadata;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedExportNonPublic != null) {
      return _unlinkedExportNonPublic.offset;
    }
    return offset;
  }

  @override
  String get uri {
    if (_unlinkedExportPublic != null) {
      return _selectedUri ??= _selectUri(
          _unlinkedExportPublic.uri, _unlinkedExportPublic.configurations);
    }
    return super.uri;
  }

  @override
  void set uri(String uri) {
    _assertNotResynthesized(_unlinkedExportPublic);
    super.uri = uri;
  }

  @override
  int get uriEnd {
    if (_unlinkedExportNonPublic != null) {
      return _unlinkedExportNonPublic.uriEnd;
    }
    return super.uriEnd;
  }

  @override
  void set uriEnd(int uriEnd) {
    _assertNotResynthesized(_unlinkedExportNonPublic);
    super.uriEnd = uriEnd;
  }

  @override
  int get uriOffset {
    if (_unlinkedExportNonPublic != null) {
      return _unlinkedExportNonPublic.uriOffset;
    }
    return super.uriOffset;
  }

  @override
  void set uriOffset(int uriOffset) {
    _assertNotResynthesized(_unlinkedExportNonPublic);
    super.uriOffset = uriOffset;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitExportElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write("export ");
    LibraryElementImpl.getImpl(exportedLibrary).appendTo(buffer);
  }
}

/// A concrete implementation of a [FieldElement].
class FieldElementImpl extends PropertyInducingElementImpl
    implements FieldElement {
  /// Initialize a newly created synthetic field element to have the given
  /// [name] at the given [offset].
  FieldElementImpl(String name, int offset) : super(name, offset);

  FieldElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode) {
    if (!linkedNode.isSynthetic) {
      var enclosingRef = enclosing.reference;

      this.getter = PropertyAccessorElementImpl_ImplicitGetter(
        this,
        reference: enclosingRef.getChild('@getter').getChild(name),
      );

      if (!isConst && !isFinal) {
        this.setter = PropertyAccessorElementImpl_ImplicitSetter(
          this,
          reference: enclosingRef.getChild('@setter').getChild(name),
        );
      }
    }
  }

  factory FieldElementImpl.forLinkedNodeFactory(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode) {
    if (enclosing.enclosingUnit.linkedContext.isConst(linkedNode)) {
      return ConstFieldElementImpl.forLinkedNode(
        enclosing,
        reference,
        linkedNode,
      );
    }
    return FieldElementImpl.forLinkedNode(enclosing, reference, linkedNode);
  }

  /// Initialize a newly created field element to have the given [name].
  FieldElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  FieldElementImpl.forSerialized(
      UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedVariable, enclosingElement);

  /// Initialize using the given serialized information.
  factory FieldElementImpl.forSerializedFactory(
      UnlinkedVariable unlinkedVariable, ClassElementImpl enclosingClass) {
    if (unlinkedVariable.initializer?.bodyExpr != null &&
        (unlinkedVariable.isConst ||
            unlinkedVariable.isFinal &&
                !unlinkedVariable.isStatic &&
                enclosingClass._hasConstConstructor)) {
      return new ConstFieldElementImpl.forSerialized(
          unlinkedVariable, enclosingClass);
    } else {
      return new FieldElementImpl.forSerialized(
          unlinkedVariable, enclosingClass);
    }
  }

  @override
  ClassElement get enclosingElement => super.enclosingElement as ClassElement;

  @override
  bool get isCovariant {
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.isCovariant;
    }
    return hasModifier(Modifier.COVARIANT);
  }

  /// Set whether this field is explicitly marked as being covariant.
  void set isCovariant(bool isCovariant) {
    _assertNotResynthesized(_unlinkedVariable);
    setModifier(Modifier.COVARIANT, isCovariant);
  }

  @override
  bool get isEnumConstant =>
      enclosingElement != null && enclosingElement.isEnum && !isSynthetic;

  @override
  bool get isStatic {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isStatic(linkedNode);
    }
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.isStatic;
    }
    return hasModifier(Modifier.STATIC);
  }

  /// Set whether this field is static.
  void set isStatic(bool isStatic) {
    _assertNotResynthesized(_unlinkedVariable);
    setModifier(Modifier.STATIC, isStatic);
  }

  @deprecated
  @override
  bool get isVirtual => true;

  @override
  ElementKind get kind => ElementKind.FIELD;

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitFieldElement(this);

  @deprecated
  @override
  AstNode computeNode() {
    if (isEnumConstant) {
      return getNodeMatching((node) => node is EnumConstantDeclaration);
    } else {
      return getNodeMatching((node) => node is VariableDeclaration);
    }
  }
}

/// A [ParameterElementImpl] that has the additional information of the
/// [FieldElement] associated with the parameter.
class FieldFormalParameterElementImpl extends ParameterElementImpl
    implements FieldFormalParameterElement {
  /// The field associated with this field formal parameter.
  FieldElement _field;

  /// Initialize a newly created parameter element to have the given [name] and
  /// [nameOffset].
  FieldFormalParameterElementImpl(String name, int nameOffset)
      : super(name, nameOffset);

  FieldFormalParameterElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created parameter element to have the given [name].
  FieldFormalParameterElementImpl.forNode(Identifier name)
      : super.forNode(name);

  /// Initialize using the given serialized information.
  FieldFormalParameterElementImpl.forSerialized(
      UnlinkedParam unlinkedParam, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedParam, enclosingElement);

  @override
  FieldElement get field {
    if (_field == null) {
      String fieldName;
      if (unlinkedParam != null) {
        fieldName = unlinkedParam.name;
      }
      if (fieldName != null) {
        Element enclosingConstructor = enclosingElement;
        if (enclosingConstructor is ConstructorElement) {
          Element enclosingClass = enclosingConstructor.enclosingElement;
          if (enclosingClass is ClassElement) {
            FieldElement field = enclosingClass.getField(fieldName);
            if (field != null && !field.isSynthetic) {
              _field = field;
            }
          }
        }
      }
    }
    return _field;
  }

  void set field(FieldElement field) {
    _assertNotResynthesized(unlinkedParam);
    _field = field;
  }

  @override
  bool get isInitializingFormal => true;

  @override
  DartType get type {
    if (linkedNode != null) {
      return _type ??= enclosingUnit.linkedContext.getType(
        linkedNode.fieldFormalParameter_type2,
      );
    }
    if (unlinkedParam != null &&
        unlinkedParam.type == null &&
        !unlinkedParam.isFunctionTyped &&
        field != null) {
      _type ??= field?.type ?? DynamicTypeImpl.instance;
    }
    return super.type;
  }

  @override
  void set type(DartType type) {
    _assertNotResynthesized(unlinkedParam);
    _type = type;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitFieldFormalParameterElement(this);
}

/// A concrete implementation of a [FunctionElement].
class FunctionElementImpl extends ExecutableElementImpl
    implements FunctionElement, FunctionTypedElementImpl {
  /// The offset to the beginning of the visible range for this element.
  int _visibleRangeOffset = 0;

  /// The length of the visible range for this element, or `-1` if this element
  /// does not have a visible range.
  int _visibleRangeLength = -1;

  /// Initialize a newly created function element to have the given [name] and
  /// [offset].
  FunctionElementImpl(String name, int offset) : super(name, offset);

  FunctionElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created function element to have the given [name].
  FunctionElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize a newly created function element to have no name and the given
  /// [nameOffset]. This is used for function expressions, that have no name.
  FunctionElementImpl.forOffset(int nameOffset) : super("", nameOffset);

  /// Initialize using the given serialized information.
  FunctionElementImpl.forSerialized(
      UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
      : super.forSerialized(serializedExecutable, enclosingElement);

  /// Synthesize an unnamed function element that takes [parameters] and returns
  /// [returnType].
  FunctionElementImpl.synthetic(
      List<ParameterElement> parameters, DartType returnType)
      : super("", -1) {
    isSynthetic = true;
    this.returnType = returnType;
    this.parameters = parameters;

    type = new FunctionTypeImpl(this);
  }

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext {
    return (enclosingElement as ElementImpl).typeParameterContext;
  }

  @override
  String get identifier {
    String identifier = super.identifier;
    Element enclosing = this.enclosingElement;
    if (enclosing is ExecutableElement) {
      identifier += "@$nameOffset";
    }
    return identifier;
  }

  @override
  bool get isEntryPoint {
    return isStatic && displayName == FunctionElement.MAIN_FUNCTION_NAME;
  }

  @override
  bool get isStatic => enclosingElement is CompilationUnitElement;

  @override
  ElementKind get kind => ElementKind.FUNCTION;

  @override
  DartType get returnType {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getType(
        linkedNode.functionDeclaration_returnType2,
      );
    }
    return super.returnType;
  }

  @override
  void set returnType(DartType returnType) {
    if (linkedNode != null) {
      enclosingUnit.linkedContext.setReturnType(linkedNode, returnType);
    }
    super.returnType = returnType;
  }

  @override
  SourceRange get visibleRange {
    if (serializedExecutable != null) {
      if (serializedExecutable.visibleLength == 0) {
        return null;
      }
      return new SourceRange(serializedExecutable.visibleOffset,
          serializedExecutable.visibleLength);
    }
    if (_visibleRangeLength < 0) {
      return null;
    }
    return new SourceRange(_visibleRangeOffset, _visibleRangeLength);
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitFunctionElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    String name = displayName;
    if (name != null) {
      buffer.write(name);
    }
    super.appendTo(buffer);
  }

  @deprecated
  @override
  FunctionDeclaration computeNode() =>
      getNodeMatching((node) => node is FunctionDeclaration);

  /// Set the visible range for this element to the range starting at the given
  /// [offset] with the given [length].
  void setVisibleRange(int offset, int length) {
    _assertNotResynthesized(serializedExecutable);
    _visibleRangeOffset = offset;
    _visibleRangeLength = length;
  }

  /// Set the parameters defined by this type alias to the given [parameters]
  /// without becoming the parent of the parameters. This should only be used by
  /// the [TypeResolverVisitor] when creating a synthetic type alias.
  void shareParameters(List<ParameterElement> parameters) {
    this._parameters = parameters;
  }

  /// Set the type parameters defined by this type alias to the given
  /// [parameters] without becoming the parent of the parameters. This should
  /// only be used by the [TypeResolverVisitor] when creating a synthetic type
  /// alias.
  void shareTypeParameters(List<TypeParameterElement> typeParameters) {
    this._typeParameterElements = typeParameters;
  }

  /// Create and return [FunctionElement]s for the given [unlinkedFunctions].
  static List<FunctionElement> resynthesizeList(
      ExecutableElementImpl executableElement,
      List<UnlinkedExecutable> unlinkedFunctions) {
    int length = unlinkedFunctions.length;
    if (length != 0) {
      List<FunctionElement> elements = new List<FunctionElement>(length);
      for (int i = 0; i < length; i++) {
        elements[i] = new FunctionElementImpl.forSerialized(
            unlinkedFunctions[i], executableElement);
      }
      return elements;
    } else {
      return const <FunctionElement>[];
    }
  }
}

/// Implementation of [FunctionElementImpl] for a function typed parameter.
class FunctionElementImpl_forFunctionTypedParameter
    extends FunctionElementImpl {
  @override
  final CompilationUnitElementImpl enclosingUnit;

  /// The enclosing function typed [ParameterElementImpl].
  final ParameterElementImpl _parameter;

  FunctionElementImpl_forFunctionTypedParameter(
      this.enclosingUnit, this._parameter)
      : super('', -1);

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext =>
      _parameter.typeParameterContext;

  @override
  bool get isSynthetic => true;
}

/// Implementation of [FunctionElementImpl] for a synthetic function element
/// that was synthesized by a LUB computation.
class FunctionElementImpl_forLUB extends FunctionElementImpl {
  final EntityRef _entityRef;

  FunctionElementImpl_forLUB(ElementImpl enclosingElement, this._entityRef)
      : super.forSerialized(null, enclosingElement);

  @override
  bool get isSynthetic => true;

  @override
  List<ParameterElement> get parameters {
    return _parameters ??= ParameterElementImpl.resynthesizeList(
        _entityRef.syntheticParams, this,
        synthetic: true);
  }

  @override
  void set parameters(List<ParameterElement> parameters) {
    assert(false);
  }

  @override
  DartType get returnType {
    return _returnType ??= enclosingUnit.resynthesizerContext
        .resolveTypeRef(this, _entityRef.syntheticReturnType);
  }

  @override
  void set returnType(DartType returnType) {
    assert(false);
  }

  @override
  FunctionType get type {
    return _type ??= new FunctionTypeImpl(this);
  }

  @override
  void set type(FunctionType type) {
    assert(false);
  }

  @override
  List<UnlinkedTypeParam> get unlinkedTypeParams => _entityRef.typeParameters;
}

/// Common internal interface shared by elements whose type is a function type.
///
/// Clients may not extend, implement or mix-in this class.
abstract class FunctionTypedElementImpl
    implements ElementImpl, FunctionTypedElement {
  void set returnType(DartType returnType);
}

/// The element used for a generic function type.
///
/// Clients may not extend, implement or mix-in this class.
class GenericFunctionTypeElementImpl extends ElementImpl
    with TypeParameterizedElementMixin
    implements GenericFunctionTypeElement, FunctionTypedElementImpl {
  /// The unlinked representation of the generic function type in the summary.
  EntityRef _entityRef;

  /// The declared return type of the function.
  DartType _returnType;

  /// The elements representing the parameters of the function.
  List<ParameterElement> _parameters;

  /// The type defined by this element.
  FunctionType _type;

  GenericFunctionTypeElementImpl.forLinkedNode(
      ElementImpl enclosingElement, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosingElement, reference, linkedNode);

  /// Initialize a newly created function element to have no name and the given
  /// [nameOffset]. This is used for function expressions, that have no name.
  GenericFunctionTypeElementImpl.forOffset(int nameOffset)
      : super("", nameOffset);

  /// Initialize from serialized information.
  GenericFunctionTypeElementImpl.forSerialized(
      ElementImpl enclosingElement, this._entityRef)
      : super.forSerialized(enclosingElement);

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext {
    return _enclosingElement.typeParameterContext;
  }

  @override
  String get identifier => '-';

  @override
  ElementKind get kind => ElementKind.GENERIC_FUNCTION_TYPE;

  @override
  List<ParameterElement> get parameters {
    if (_parameters == null) {
      if (linkedNode != null) {
        var context = enclosingUnit.linkedContext;
        return _parameters = ParameterElementImpl.forLinkedNodeList(
          this,
          context,
          reference.getChild('@parameter'),
          context.getFormalParameters(linkedNode),
        );
      }
      if (_entityRef != null) {
        _parameters = ParameterElementImpl.resynthesizeList(
            _entityRef.syntheticParams, this);
      }
    }
    return _parameters ?? const <ParameterElement>[];
  }

  /// Set the parameters defined by this function type element to the given
  /// [parameters].
  void set parameters(List<ParameterElement> parameters) {
    _assertNotResynthesized(_entityRef);
    for (ParameterElement parameter in parameters) {
      (parameter as ParameterElementImpl).enclosingElement = this;
    }
    this._parameters = parameters;
  }

  @override
  DartType get returnType {
    if (_returnType == null) {
      if (linkedNode != null) {
        var context = enclosingUnit.linkedContext;
        return _returnType = context.getReturnType(linkedNode);
      }
      if (_entityRef != null) {
        _returnType = enclosingUnit.resynthesizerContext.resolveTypeRef(
            this, _entityRef.syntheticReturnType,
            defaultVoid: false, declaredType: true);
      }
    }
    return _returnType;
  }

  /// Set the return type defined by this function type element to the given
  /// [returnType].
  void set returnType(DartType returnType) {
    _assertNotResynthesized(_entityRef);
    _returnType = _checkElementOfType(returnType);
  }

  @override
  FunctionType get type {
    _type ??= new FunctionTypeImpl(this);
    return _type;
  }

  /// Set the function type defined by this function type element to the given
  /// [type].
  void set type(FunctionType type) {
    _assertNotResynthesized(_entityRef);
    _type = type;
  }

  @override
  List<TypeParameterElement> get typeParameters {
    if (linkedNode != null) {
      if (linkedNode.kind == LinkedNodeKind.functionTypeAlias) {
        return const <TypeParameterElement>[];
      }
    }
    return super.typeParameters;
  }

  /// Set the type parameters defined by this function type element to the given
  /// [typeParameters].
  void set typeParameters(List<TypeParameterElement> typeParameters) {
    _assertNotResynthesized(_entityRef);
    for (TypeParameterElement parameter in typeParameters) {
      (parameter as TypeParameterElementImpl).enclosingElement = this;
    }
    this._typeParameterElements = typeParameters;
  }

  @override
  List<UnlinkedTypeParam> get unlinkedTypeParams => _entityRef?.typeParameters;

  @override
  T accept<T>(ElementVisitor<T> visitor) {
    return visitor.visitGenericFunctionTypeElement(this);
  }

  @override
  void appendTo(StringBuffer buffer) {
    DartType type = returnType;
    if (type is TypeImpl) {
      type.appendTo(buffer, new HashSet<TypeImpl>());
      buffer.write(' Function');
    } else {
      buffer.write('Function');
    }
    List<TypeParameterElement> typeParams = typeParameters;
    int typeParameterCount = typeParams.length;
    if (typeParameterCount > 0) {
      buffer.write('<');
      for (int i = 0; i < typeParameterCount; i++) {
        if (i > 0) {
          buffer.write(', ');
        }
        (typeParams[i] as TypeParameterElementImpl).appendTo(buffer);
      }
      buffer.write('>');
    }
    List<ParameterElement> params = parameters;
    buffer.write('(');
    for (int i = 0; i < params.length; i++) {
      if (i > 0) {
        buffer.write(', ');
      }
      (params[i] as ParameterElementImpl).appendTo(buffer);
    }
    buffer.write(')');
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    _safelyVisitPossibleChild(returnType, visitor);
    safelyVisitChildren(typeParameters, visitor);
    safelyVisitChildren(parameters, visitor);
  }
}

/// A function type alias of the form
///     `typedef` identifier typeParameters = genericFunctionType;
///
/// Clients may not extend, implement or mix-in this class.
class GenericTypeAliasElementImpl extends ElementImpl
    with TypeParameterizedElementMixin, SimplyBoundableMixin
    implements GenericTypeAliasElement {
  /// The unlinked representation of the type in the summary.
  final UnlinkedTypedef _unlinkedTypedef;

  /// The element representing the generic function type.
  GenericFunctionTypeElementImpl _function;

  /// The type of function defined by this type alias.
  FunctionType _type;

  /// Initialize a newly created type alias element to have the given [name].
  GenericTypeAliasElementImpl(String name, int offset)
      : _unlinkedTypedef = null,
        super(name, offset);

  GenericTypeAliasElementImpl.forLinkedNode(
      CompilationUnitElementImpl enclosingUnit,
      Reference reference,
      LinkedNode linkedNode)
      : _unlinkedTypedef = null,
        super.forLinkedNode(enclosingUnit, reference, linkedNode);

  /// Initialize a newly created type alias element to have the given [name].
  GenericTypeAliasElementImpl.forNode(Identifier name)
      : _unlinkedTypedef = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  GenericTypeAliasElementImpl.forSerialized(
      this._unlinkedTypedef, CompilationUnitElementImpl enclosingUnit)
      : super.forSerialized(enclosingUnit);

  @override
  int get codeLength {
    if (_unlinkedTypedef != null) {
      return _unlinkedTypedef.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (_unlinkedTypedef != null) {
      return _unlinkedTypedef.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  String get displayName => name;

  @override
  String get documentationComment {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getCommentText(
        linkedNode.annotatedNode_comment,
      );
    }
    if (_unlinkedTypedef != null) {
      return _unlinkedTypedef.documentationComment?.text;
    }
    return super.documentationComment;
  }

  @override
  CompilationUnitElement get enclosingElement =>
      super.enclosingElement as CompilationUnitElement;

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;

  @override
  CompilationUnitElementImpl get enclosingUnit =>
      _enclosingElement as CompilationUnitElementImpl;

  @override
  GenericFunctionTypeElementImpl get function {
    if (_function != null) return _function;

    if (linkedNode != null) {
      if (linkedNode.kind == LinkedNodeKind.genericTypeAlias) {
        _function = GenericFunctionTypeElementImpl.forLinkedNode(
          this,
          reference.getChild('@function'),
          linkedNode.genericTypeAlias_functionType,
        );
      } else {
        return _function = GenericFunctionTypeElementImpl.forLinkedNode(
          this,
          reference.getChild('@function'),
          linkedNode,
        );
      }
      return _function;
    }

    if (_unlinkedTypedef != null) {
      if (_unlinkedTypedef.style == TypedefStyle.genericFunctionType) {
        DartType type = enclosingUnit.resynthesizerContext.resolveTypeRef(
            this, _unlinkedTypedef.returnType,
            declaredType: true);
        if (type is FunctionType) {
          Element element = type.element;
          if (element is GenericFunctionTypeElement) {
            (element as GenericFunctionTypeElementImpl).enclosingElement = this;
            _function = element;
          }
        }
      } else {
        _function = new GenericFunctionTypeElementImpl.forOffset(-1);
        _function.enclosingElement = this;
        _function.returnType = enclosingUnit.resynthesizerContext
            .resolveTypeRef(_function, _unlinkedTypedef.returnType,
                declaredType: true);
        _function.parameters = ParameterElementImpl.resynthesizeList(
            _unlinkedTypedef.parameters, _function);
      }
    }

    return _function;
  }

  /// Set the function element representing the generic function type on the
  /// right side of the equals to the given [function].
  void set function(GenericFunctionTypeElementImpl function) {
    _assertNotResynthesized(_unlinkedTypedef);
    if (function != null) {
      function.enclosingElement = this;
    }
    _function = function;
  }

  @override
  ElementKind get kind => ElementKind.FUNCTION_TYPE_ALIAS;

  @override
  List<ElementAnnotation> get metadata {
    if (_unlinkedTypedef != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, _unlinkedTypedef.annotations);
    }
    return super.metadata;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (_unlinkedTypedef != null) {
      return _unlinkedTypedef.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedTypedef != null) {
      return _unlinkedTypedef.nameOffset;
    }
    return offset;
  }

  @override
  List<ParameterElement> get parameters =>
      function?.parameters ?? const <ParameterElement>[];

  @override
  DartType get returnType => function?.returnType;

  @override
  FunctionType get type {
    _type ??= new FunctionTypeImpl.forTypedef(this);
    return _type;
  }

  void set type(FunctionType type) {
    _assertNotResynthesized(_unlinkedTypedef);
    _type = type;
  }

  /// Set the type parameters defined for this type to the given
  /// [typeParameters].
  void set typeParameters(List<TypeParameterElement> typeParameters) {
    _assertNotResynthesized(_unlinkedTypedef);
    for (TypeParameterElement typeParameter in typeParameters) {
      (typeParameter as TypeParameterElementImpl).enclosingElement = this;
    }
    this._typeParameterElements = typeParameters;
  }

  @override
  List<UnlinkedTypeParam> get unlinkedTypeParams =>
      _unlinkedTypedef?.typeParameters;

  @override
  int get _notSimplyBoundedSlot => _unlinkedTypedef?.notSimplyBoundedSlot;

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitFunctionTypeAliasElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write("typedef ");
    buffer.write(displayName);
    var typeParameters = this.typeParameters;
    int typeParameterCount = typeParameters.length;
    if (typeParameterCount > 0) {
      buffer.write("<");
      for (int i = 0; i < typeParameterCount; i++) {
        if (i > 0) {
          buffer.write(", ");
        }
        (typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
      }
      buffer.write(">");
    }
    buffer.write(" = ");
    if (function != null) {
      function.appendTo(buffer);
    }
  }

  @deprecated
  @override
  GenericTypeAlias computeNode() =>
      getNodeMatching((node) => node is GenericTypeAlias);

  @override
  ElementImpl getChild(String identifier) {
    for (TypeParameterElement typeParameter in typeParameters) {
      TypeParameterElementImpl typeParameterImpl = typeParameter;
      if (typeParameterImpl.identifier == identifier) {
        return typeParameterImpl;
      }
    }
    return null;
  }

  @override
  FunctionType instantiate(List<DartType> argumentTypes) {
    return doInstantiate(this, argumentTypes);
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    safelyVisitChildren(typeParameters, visitor);
    function?.accept(visitor);
  }

  static FunctionType doInstantiate(
      FunctionTypeAliasElement element, List<DartType> argumentTypes) {
    if (argumentTypes.length != element.typeParameters.length) {
      throw new ArgumentError('Wrong number of type arguments supplied');
    }
    if (element.typeParameters.isEmpty) return element.function.type;
    return typeAfterSubstitution(element, argumentTypes);
  }

  /// Return the type of the function defined by this typedef after substituting
  /// the given [typeArguments] for the type parameters defined for this typedef
  /// (but not the type parameters defined by the function). If the number of
  /// [typeArguments] does not match the number of type parameters, then
  /// `dynamic` will be used in place of each of the type arguments.
  static FunctionType typeAfterSubstitution(
      FunctionTypeAliasElement element, List<DartType> typeArguments) {
    GenericFunctionTypeElement function = element.function;
    if (function == null) {
      return null;
    }
    FunctionType functionType = function.type;
    List<TypeParameterElement> parameterElements = element.typeParameters;
    List<DartType> parameterTypes =
        TypeParameterTypeImpl.getTypes(parameterElements);
    int parameterCount = parameterTypes.length;
    if (typeArguments == null ||
        parameterElements.length != typeArguments.length) {
      DartType dynamicType = DynamicElementImpl.instance.type;
      typeArguments = new List<DartType>.filled(parameterCount, dynamicType);
    }
    return functionType.substitute2(typeArguments, parameterTypes);
  }
}

/// A concrete implementation of a [HideElementCombinator].
class HideElementCombinatorImpl implements HideElementCombinator {
  /// The unlinked representation of the combinator in the summary.
  final UnlinkedCombinator _unlinkedCombinator;

  /// The names that are not to be made visible in the importing library even if
  /// they are defined in the imported library.
  List<String> _hiddenNames;

  HideElementCombinatorImpl() : _unlinkedCombinator = null;

  /// Initialize using the given serialized information.
  HideElementCombinatorImpl.forSerialized(this._unlinkedCombinator);

  @override
  List<String> get hiddenNames {
    if (_unlinkedCombinator != null) {
      _hiddenNames ??= _unlinkedCombinator.hides.toList(growable: false);
    }
    return _hiddenNames ?? const <String>[];
  }

  void set hiddenNames(List<String> hiddenNames) {
    _assertNotResynthesized(_unlinkedCombinator);
    _hiddenNames = hiddenNames;
  }

  @override
  String toString() {
    StringBuffer buffer = new StringBuffer();
    buffer.write("show ");
    int count = hiddenNames.length;
    for (int i = 0; i < count; i++) {
      if (i > 0) {
        buffer.write(", ");
      }
      buffer.write(hiddenNames[i]);
    }
    return buffer.toString();
  }
}

/// A concrete implementation of an [ImportElement].
class ImportElementImpl extends UriReferencedElementImpl
    implements ImportElement {
  /// The unlinked representation of the import in the summary.
  final UnlinkedImport _unlinkedImport;

  /// The index of the dependency in the `imports` list.
  final int _linkedDependency;

  /// The offset of the prefix of this import in the file that contains the this
  /// import directive, or `-1` if this import is synthetic.
  int _prefixOffset = 0;

  /// The library that is imported into this library by this import directive.
  LibraryElement _importedLibrary;

  /// The combinators that were specified as part of the import directive in the
  /// order in which they were specified.
  List<NamespaceCombinator> _combinators;

  /// The prefix that was specified as part of the import directive, or `null
  ///` if there was no prefix specified.
  PrefixElement _prefix;

  /// The URI that was selected based on the declared variables.
  String _selectedUri;

  /// The cached value of [namespace].
  Namespace _namespace;

  /// Initialize a newly created import element at the given [offset].
  /// The offset may be `-1` if the import is synthetic.
  ImportElementImpl(int offset)
      : _unlinkedImport = null,
        _linkedDependency = null,
        super(null, offset);

  ImportElementImpl.forLinkedNode(
      LibraryElementImpl enclosing, LinkedNode linkedNode)
      : _unlinkedImport = null,
        _linkedDependency = null,
        super.forLinkedNode(enclosing, null, linkedNode);

  /// Initialize using the given serialized information.
  ImportElementImpl.forSerialized(this._unlinkedImport, this._linkedDependency,
      LibraryElementImpl enclosingLibrary)
      : super.forSerialized(enclosingLibrary);

  @override
  List<NamespaceCombinator> get combinators {
    if (_combinators == null) {
      if (_unlinkedImport != null) {
        _combinators = _buildCombinators(_unlinkedImport.combinators);
      }
    }
    return _combinators ?? const <NamespaceCombinator>[];
  }

  void set combinators(List<NamespaceCombinator> combinators) {
    _assertNotResynthesized(_unlinkedImport);
    _combinators = combinators;
  }

  /// Set whether this import is for a deferred library.
  void set deferred(bool isDeferred) {
    _assertNotResynthesized(_unlinkedImport);
    setModifier(Modifier.DEFERRED, isDeferred);
  }

  @override
  CompilationUnitElementImpl get enclosingUnit {
    LibraryElementImpl enclosingLibrary = enclosingElement;
    return enclosingLibrary._definingCompilationUnit;
  }

  @override
  String get identifier => "${importedLibrary.identifier}@$nameOffset";

  @override
  LibraryElement get importedLibrary {
    if (_importedLibrary != null) return _importedLibrary;

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var relativeUriStr = context.getStringContent(
        linkedNode.uriBasedDirective_uri,
      );
      var relativeUri = Uri.parse(relativeUriStr);
      var uri = resolveRelativeUri(librarySource.uri, relativeUri);
      var elementFactory = context.bundleContext.elementFactory;
      return _importedLibrary = elementFactory.libraryOfUri('$uri');
    }
    if (_linkedDependency != null) {
      if (_importedLibrary == null) {
        LibraryElementImpl library = enclosingElement as LibraryElementImpl;
        if (_linkedDependency == 0) {
          _importedLibrary = library;
        } else {
          _importedLibrary = library.resynthesizerContext
              .buildImportedLibrary(_linkedDependency);
        }
      }
    }
    return _importedLibrary;
  }

  void set importedLibrary(LibraryElement importedLibrary) {
    _assertNotResynthesized(_unlinkedImport);
    _importedLibrary = importedLibrary;
  }

  @override
  bool get isDeferred {
    if (_unlinkedImport != null) {
      return _unlinkedImport.isDeferred;
    }
    return hasModifier(Modifier.DEFERRED);
  }

  @override
  bool get isSynthetic {
    if (_unlinkedImport != null) {
      return _unlinkedImport.isImplicit;
    }
    return super.isSynthetic;
  }

  @override
  ElementKind get kind => ElementKind.IMPORT;

  @override
  List<ElementAnnotation> get metadata {
    if (linkedNode != null) {
      if (_metadata != null) return _metadata;
      var metadata = enclosingUnit.linkedContext.getMetadataOrEmpty(linkedNode);
      return _metadata = _buildAnnotations2(enclosingUnit, metadata);
    }
    if (_metadata == null) {
      if (_unlinkedImport != null) {
        return _metadata = _buildAnnotations(
            library.definingCompilationUnit, _unlinkedImport.annotations);
      }
    }
    return super.metadata;
  }

  void set metadata(List<ElementAnnotation> metadata) {
    _assertNotResynthesized(_unlinkedImport);
    super.metadata = metadata;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedImport != null) {
      if (_unlinkedImport.isImplicit) {
        return -1;
      }
      return _unlinkedImport.offset;
    }
    return offset;
  }

  @override
  Namespace get namespace {
    return _namespace ??=
        new NamespaceBuilder().createImportNamespaceForDirective(this);
  }

  PrefixElement get prefix {
    if (_prefix == null) {
      if (_unlinkedImport != null && _unlinkedImport.prefixReference != 0) {
        LibraryElementImpl library = enclosingElement as LibraryElementImpl;
        _prefix = new PrefixElementImpl.forSerialized(_unlinkedImport, library);
      }
    }
    return _prefix;
  }

  void set prefix(PrefixElement prefix) {
    _assertNotResynthesized(_unlinkedImport);
    _prefix = prefix;
  }

  @override
  int get prefixOffset {
    if (_unlinkedImport != null) {
      return _unlinkedImport.prefixOffset;
    }
    return _prefixOffset;
  }

  void set prefixOffset(int prefixOffset) {
    _assertNotResynthesized(_unlinkedImport);
    _prefixOffset = prefixOffset;
  }

  @override
  String get uri {
    if (_unlinkedImport != null) {
      if (_unlinkedImport.isImplicit) {
        return null;
      }
      return _selectedUri ??=
          _selectUri(_unlinkedImport.uri, _unlinkedImport.configurations);
    }
    return super.uri;
  }

  @override
  void set uri(String uri) {
    _assertNotResynthesized(_unlinkedImport);
    super.uri = uri;
  }

  @override
  int get uriEnd {
    if (_unlinkedImport != null) {
      if (_unlinkedImport.isImplicit) {
        return -1;
      }
      return _unlinkedImport.uriEnd;
    }
    return super.uriEnd;
  }

  @override
  void set uriEnd(int uriEnd) {
    _assertNotResynthesized(_unlinkedImport);
    super.uriEnd = uriEnd;
  }

  @override
  int get uriOffset {
    if (_unlinkedImport != null) {
      if (_unlinkedImport.isImplicit) {
        return -1;
      }
      return _unlinkedImport.uriOffset;
    }
    return super.uriOffset;
  }

  @override
  void set uriOffset(int uriOffset) {
    _assertNotResynthesized(_unlinkedImport);
    super.uriOffset = uriOffset;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitImportElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write("import ");
    LibraryElementImpl.getImpl(importedLibrary).appendTo(buffer);
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    prefix?.accept(visitor);
  }

  static List<NamespaceCombinator> _buildCombinators(
      List<UnlinkedCombinator> unlinkedCombinators) {
    int length = unlinkedCombinators.length;
    if (length != 0) {
      List<NamespaceCombinator> combinators =
          new List<NamespaceCombinator>(length);
      for (int i = 0; i < length; i++) {
        UnlinkedCombinator unlinkedCombinator = unlinkedCombinators[i];
        combinators[i] = unlinkedCombinator.shows.isNotEmpty
            ? new ShowElementCombinatorImpl.forSerialized(unlinkedCombinator)
            : new HideElementCombinatorImpl.forSerialized(unlinkedCombinator);
      }
      return combinators;
    } else {
      return const <NamespaceCombinator>[];
    }
  }
}

/// A concrete implementation of a [LabelElement].
class LabelElementImpl extends ElementImpl implements LabelElement {
  /// A flag indicating whether this label is associated with a `switch`
  /// statement.
  // TODO(brianwilkerson) Make this a modifier.
  final bool _onSwitchStatement;

  /// A flag indicating whether this label is associated with a `switch` member
  /// (`case` or `default`).
  // TODO(brianwilkerson) Make this a modifier.
  final bool _onSwitchMember;

  /// Initialize a newly created label element to have the given [name].
  /// [onSwitchStatement] should be `true` if this label is associated with a
  /// `switch` statement and [onSwitchMember] should be `true` if this label is
  /// associated with a `switch` member.
  LabelElementImpl(String name, int nameOffset, this._onSwitchStatement,
      this._onSwitchMember)
      : super(name, nameOffset);

  /// Initialize a newly created label element to have the given [name].
  /// [_onSwitchStatement] should be `true` if this label is associated with a
  /// `switch` statement and [_onSwitchMember] should be `true` if this label is
  /// associated with a `switch` member.
  LabelElementImpl.forNode(
      Identifier name, this._onSwitchStatement, this._onSwitchMember)
      : super.forNode(name);

  @override
  String get displayName => name;

  @override
  ExecutableElement get enclosingElement =>
      super.enclosingElement as ExecutableElement;

  /// Return `true` if this label is associated with a `switch` member (`case
  /// ` or`default`).
  bool get isOnSwitchMember => _onSwitchMember;

  /// Return `true` if this label is associated with a `switch` statement.
  bool get isOnSwitchStatement => _onSwitchStatement;

  @override
  ElementKind get kind => ElementKind.LABEL;

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitLabelElement(this);
}

/// A concrete implementation of a [LibraryElement].
class LibraryElementImpl extends ElementImpl implements LibraryElement {
  /// The analysis context in which this library is defined.
  final AnalysisContext context;

  @override
  final AnalysisSession session;

  final LibraryResynthesizerContext resynthesizerContext;

  final UnlinkedUnit unlinkedDefiningUnit;

  /// The context of the defining unit.
  final LinkedUnitContext linkedContext;

  /// The compilation unit that defines this library.
  CompilationUnitElement _definingCompilationUnit;

  /// The entry point for this library, or `null` if this library does not have
  /// an entry point.
  FunctionElement _entryPoint;

  /// A list containing specifications of all of the imports defined in this
  /// library.
  List<ImportElement> _imports;

  /// A list containing specifications of all of the exports defined in this
  /// library.
  List<ExportElement> _exports;

  /// A list containing the strongly connected component in the import/export
  /// graph in which the current library resides.  Computed on demand, null
  /// if not present.  If _libraryCycle is set, then the _libraryCycle field
  /// for all libraries reachable from this library in the import/export graph
  /// is also set.
  List<LibraryElement> _libraryCycle = null;

  /// A list containing all of the compilation units that are included in this
  /// library using a `part` directive.
  List<CompilationUnitElement> _parts = const <CompilationUnitElement>[];

  /// The element representing the synthetic function `loadLibrary` that is
  /// defined for this library, or `null` if the element has not yet been
  /// created.
  FunctionElement _loadLibraryFunction;

  @override
  final int nameLength;

  /// The export [Namespace] of this library, `null` if it has not been
  /// computed yet.
  Namespace _exportNamespace;

  /// The public [Namespace] of this library, `null` if it has not been
  /// computed yet.
  Namespace _publicNamespace;

  /// A bit-encoded form of the capabilities associated with this library.
  int _resolutionCapabilities = 0;

  /// The cached list of prefixes.
  List<PrefixElement> _prefixes;

  /// Initialize a newly created library element in the given [context] to have
  /// the given [name] and [offset].
  LibraryElementImpl(
      this.context, this.session, String name, int offset, this.nameLength)
      : resynthesizerContext = null,
        unlinkedDefiningUnit = null,
        linkedContext = null,
        super(name, offset);

  LibraryElementImpl.forLinkedNode(
      this.context,
      this.session,
      String name,
      int offset,
      this.nameLength,
      this.linkedContext,
      Reference reference,
      LinkedNode linkedNode)
      : resynthesizerContext = null,
        unlinkedDefiningUnit = null,
        super.forLinkedNode(null, reference, linkedNode) {
    _name = name;
    _nameOffset = offset;
  }

  /// Initialize a newly created library element in the given [context] to have
  /// the given [name].
  LibraryElementImpl.forNode(this.context, this.session, LibraryIdentifier name)
      : nameLength = name != null ? name.length : 0,
        resynthesizerContext = null,
        unlinkedDefiningUnit = null,
        linkedContext = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  LibraryElementImpl.forSerialized(
      this.context,
      this.session,
      String name,
      int offset,
      this.nameLength,
      this.resynthesizerContext,
      this.unlinkedDefiningUnit)
      : linkedContext = null,
        super.forSerialized(null) {
    _name = name;
    _nameOffset = offset;
    setResolutionCapability(
        LibraryResolutionCapability.resolvedTypeNames, true);
    setResolutionCapability(
        LibraryResolutionCapability.constantExpressions, true);
  }

  @override
  int get codeLength {
    CompilationUnitElement unit = _definingCompilationUnit;
    if (unit is CompilationUnitElementImpl) {
      return unit.codeLength;
    }
    return null;
  }

  @override
  int get codeOffset {
    CompilationUnitElement unit = _definingCompilationUnit;
    if (unit is CompilationUnitElementImpl) {
      return unit.codeOffset;
    }
    return null;
  }

  @override
  CompilationUnitElement get definingCompilationUnit =>
      _definingCompilationUnit;

  /// Set the compilation unit that defines this library to the given
  ///  compilation[unit].
  void set definingCompilationUnit(CompilationUnitElement unit) {
    assert((unit as CompilationUnitElementImpl).librarySource == unit.source);
    (unit as CompilationUnitElementImpl).enclosingElement = this;
    this._definingCompilationUnit = unit;
  }

  @override
  String get documentationComment {
    if (unlinkedDefiningUnit != null) {
      return unlinkedDefiningUnit.libraryDocumentationComment?.text;
    }
    return super.documentationComment;
  }

  FunctionElement get entryPoint {
    if (resynthesizerContext != null) {
      _entryPoint ??= resynthesizerContext.findEntryPoint();
    }
    return _entryPoint;
  }

  void set entryPoint(FunctionElement entryPoint) {
    _entryPoint = entryPoint;
  }

  @override
  List<LibraryElement> get exportedLibraries {
    HashSet<LibraryElement> libraries = new HashSet<LibraryElement>();
    for (ExportElement element in exports) {
      LibraryElement library = element.exportedLibrary;
      if (library != null) {
        libraries.add(library);
      }
    }
    return libraries.toList(growable: false);
  }

  @override
  Namespace get exportNamespace {
    if (resynthesizerContext != null) {
      _exportNamespace ??= resynthesizerContext.buildExportNamespace();
    }
    return _exportNamespace;
  }

  void set exportNamespace(Namespace exportNamespace) {
    _exportNamespace = exportNamespace;
  }

  @override
  List<ExportElement> get exports {
    if (_exports == null) {
      if (unlinkedDefiningUnit != null) {
        List<UnlinkedExportNonPublic> unlinkedNonPublicExports =
            unlinkedDefiningUnit.exports;
        List<UnlinkedExportPublic> unlinkedPublicExports =
            unlinkedDefiningUnit.publicNamespace.exports;
        assert(unlinkedDefiningUnit.exports.length ==
            unlinkedPublicExports.length);
        int length = unlinkedNonPublicExports.length;
        if (length != 0) {
          List<ExportElement> exports = new List<ExportElement>();
          for (int i = 0; i < length; i++) {
            UnlinkedExportPublic serializedExportPublic =
                unlinkedPublicExports[i];
            UnlinkedExportNonPublic serializedExportNonPublic =
                unlinkedNonPublicExports[i];
            ExportElementImpl exportElement =
                new ExportElementImpl.forSerialized(
                    serializedExportPublic, serializedExportNonPublic, library);
            exports.add(exportElement);
          }
          _exports = exports;
        } else {
          _exports = const <ExportElement>[];
        }
      }
    }
    return _exports ?? const <ExportElement>[];
  }

  /// Set the specifications of all of the exports defined in this library to
  /// the given list of [exports].
  void set exports(List<ExportElement> exports) {
    _assertNotResynthesized(unlinkedDefiningUnit);
    for (ExportElement exportElement in exports) {
      (exportElement as ExportElementImpl).enclosingElement = this;
    }
    this._exports = exports;
  }

  @override
  bool get hasExtUri {
    if (unlinkedDefiningUnit != null) {
      List<UnlinkedImport> unlinkedImports = unlinkedDefiningUnit.imports;
      for (UnlinkedImport import in unlinkedImports) {
        if (DartUriResolver.isDartExtUri(import.uri)) {
          return true;
        }
      }
      return false;
    }
    return hasModifier(Modifier.HAS_EXT_URI);
  }

  /// Set whether this library has an import of a "dart-ext" URI.
  void set hasExtUri(bool hasExtUri) {
    setModifier(Modifier.HAS_EXT_URI, hasExtUri);
  }

  @override
  bool get hasLoadLibraryFunction {
    if (_definingCompilationUnit.hasLoadLibraryFunction) {
      return true;
    }
    for (int i = 0; i < _parts.length; i++) {
      if (_parts[i].hasLoadLibraryFunction) {
        return true;
      }
    }
    return false;
  }

  @override
  String get identifier => _definingCompilationUnit.source.encoding;

  @override
  List<LibraryElement> get importedLibraries {
    HashSet<LibraryElement> libraries = new HashSet<LibraryElement>();
    for (ImportElement element in imports) {
      LibraryElement library = element.importedLibrary;
      if (library != null) {
        libraries.add(library);
      }
    }
    return libraries.toList(growable: false);
  }

  @override
  List<ImportElement> get imports {
    if (_imports == null) {
      if (linkedNode != null) {
        return _imports = linkedNode.compilationUnit_directives
            .where((node) => node.kind == LinkedNodeKind.importDirective)
            .map((node) {
          return ImportElementImpl.forLinkedNode(this, node);
        }).toList();
      }
      if (unlinkedDefiningUnit != null) {
        _imports = buildImportsFromSummary(this, unlinkedDefiningUnit.imports,
            resynthesizerContext.linkedLibrary.importDependencies);
      }
    }
    return _imports ?? const <ImportElement>[];
  }

  /// Set the specifications of all of the imports defined in this library to
  /// the given list of [imports].
  void set imports(List<ImportElement> imports) {
    _assertNotResynthesized(unlinkedDefiningUnit);
    for (ImportElement importElement in imports) {
      (importElement as ImportElementImpl).enclosingElement = this;
      PrefixElementImpl prefix = importElement.prefix as PrefixElementImpl;
      if (prefix != null) {
        prefix.enclosingElement = this;
      }
    }
    this._imports = imports;
    this._prefixes = null;
  }

  @override
  bool get isBrowserApplication =>
      entryPoint != null && isOrImportsBrowserLibrary;

  @override
  bool get isDartAsync => name == "dart.async";

  @override
  bool get isDartCore => name == "dart.core";

  @override
  bool get isInSdk {
    Uri uri = definingCompilationUnit.source?.uri;
    if (uri != null) {
      return DartUriResolver.isDartUri(uri);
    }
    return false;
  }

  /// Return `true` if the receiver directly or indirectly imports the
  /// 'dart:html' libraries.
  bool get isOrImportsBrowserLibrary {
    List<LibraryElement> visited = new List<LibraryElement>();
    Source htmlLibSource = context.sourceFactory.forUri(DartSdk.DART_HTML);
    visited.add(this);
    for (int index = 0; index < visited.length; index++) {
      LibraryElement library = visited[index];
      Source source = library.definingCompilationUnit.source;
      if (source == htmlLibSource) {
        return true;
      }
      for (LibraryElement importedLibrary in library.importedLibraries) {
        if (!visited.contains(importedLibrary)) {
          visited.add(importedLibrary);
        }
      }
      for (LibraryElement exportedLibrary in library.exportedLibraries) {
        if (!visited.contains(exportedLibrary)) {
          visited.add(exportedLibrary);
        }
      }
    }
    return false;
  }

  @override
  bool get isResynthesized {
    return resynthesizerContext != null;
  }

  @override
  ElementKind get kind => ElementKind.LIBRARY;

  @override
  LibraryElement get library => this;

  @override
  List<LibraryElement> get libraryCycle {
    if (_libraryCycle != null) {
      return _libraryCycle;
    }

    // Global counter for this run of the algorithm
    int counter = 0;
    // The discovery times of each library
    Map<LibraryElementImpl, int> indices = {};
    // The set of scc candidates
    Set<LibraryElementImpl> active = new Set();
    // The stack of discovered elements
    List<LibraryElementImpl> stack = [];
    // For a given library that has not yet been processed by this run of the
    // algorithm, compute the strongly connected components.
    int scc(LibraryElementImpl library) {
      int index = counter++;
      int root = index;
      indices[library] = index;
      active.add(library);
      stack.add(library);
      LibraryElementImpl getActualLibrary(LibraryElement lib) {
        // TODO(paulberry): this means that computing a library cycle will be
        // expensive for libraries resynthesized from summaries, since it will
        // require fully resynthesizing all the libraries in the cycle as well
        // as any libraries they import or export.  Try to find a better way.
        if (lib is LibraryElementHandle) {
          return lib.actualElement;
        } else {
          return lib;
        }
      }

      void recurse(LibraryElementImpl child) {
        if (!indices.containsKey(child)) {
          // We haven't visited this child yet, so recurse on the child,
          // returning the lowest numbered node reachable from the child.  If
          // the child can reach a root which is lower numbered than anything
          // we've reached so far, update the root.
          root = min(root, scc(child));
        } else if (active.contains(child)) {
          // The child has been visited, but has not yet been placed into a
          // component.  If the child is higher than anything we've seen so far
          // update the root appropriately.
          root = min(root, indices[child]);
        }
      }

      // Recurse on all of the children in the import/export graph, filtering
      // out those for which library cycles have already been computed.
      library.exportedLibraries
          .map(getActualLibrary)
          .where((l) => l._libraryCycle == null)
          .forEach(recurse);
      library.importedLibraries
          .map(getActualLibrary)
          .where((l) => l._libraryCycle == null)
          .forEach(recurse);

      if (root == index) {
        // This is the root of a strongly connected component.
        // Pop the elements, and share the component across all
        // of the elements.
        List<LibraryElement> component = <LibraryElement>[];
        LibraryElementImpl cur = null;
        do {
          cur = stack.removeLast();
          active.remove(cur);
          component.add(cur);
          cur._libraryCycle = component;
        } while (cur != library);
      }
      return root;
    }

    scc(library);
    return _libraryCycle;
  }

  @override
  FunctionElement get loadLibraryFunction {
    assert(_loadLibraryFunction != null);
    return _loadLibraryFunction;
  }

  @override
  List<ElementAnnotation> get metadata {
    if (linkedNode != null) {
      if (_metadata != null) return _metadata;
      CompilationUnitElementImpl enclosingUnit = _definingCompilationUnit;
      var context = enclosingUnit.linkedContext;
      var metadata = context.getMetadataOrEmpty(linkedNode);
      return _metadata = _buildAnnotations2(enclosingUnit, metadata);
    }
    if (_metadata == null) {
      if (unlinkedDefiningUnit != null) {
        _metadata = _buildAnnotations(
            _definingCompilationUnit as CompilationUnitElementImpl,
            unlinkedDefiningUnit.libraryAnnotations);
        return _metadata;
      }
    }
    return super.metadata;
  }

  @override
  List<CompilationUnitElement> get parts => _parts;

  /// Set the compilation units that are included in this library using a `part`
  /// directive to the given list of [parts].
  void set parts(List<CompilationUnitElement> parts) {
    for (CompilationUnitElement compilationUnit in parts) {
      assert((compilationUnit as CompilationUnitElementImpl).librarySource ==
          source);
      (compilationUnit as CompilationUnitElementImpl).enclosingElement = this;
    }
    this._parts = parts;
  }

  @override
  List<PrefixElement> get prefixes =>
      _prefixes ??= buildPrefixesFromImports(imports);

  @override
  Namespace get publicNamespace {
    if (resynthesizerContext != null) {
      _publicNamespace ??= resynthesizerContext.buildPublicNamespace();
    }
    return _publicNamespace;
  }

  void set publicNamespace(Namespace publicNamespace) {
    _publicNamespace = publicNamespace;
  }

  @override
  Source get source {
    if (_definingCompilationUnit == null) {
      return null;
    }
    return _definingCompilationUnit.source;
  }

  @override
  Iterable<Element> get topLevelElements sync* {
    for (var unit in units) {
      yield* unit.accessors;
      yield* unit.enums;
      yield* unit.functionTypeAliases;
      yield* unit.functions;
      yield* unit.mixins;
      yield* unit.topLevelVariables;
      yield* unit.types;
    }
  }

  @override
  List<CompilationUnitElement> get units {
    List<CompilationUnitElement> units = new List<CompilationUnitElement>();
    units.add(_definingCompilationUnit);
    units.addAll(_parts);
    return units;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitLibraryElement(this);

  /// Create the [FunctionElement] to be returned by [loadLibraryFunction],
  /// using types provided by [typeProvider].
  void createLoadLibraryFunction(TypeProvider typeProvider) {
    _loadLibraryFunction =
        createLoadLibraryFunctionForLibrary(typeProvider, this);
  }

  @override
  ElementImpl getChild(String identifier) {
    CompilationUnitElementImpl unitImpl = _definingCompilationUnit;
    if (unitImpl.identifier == identifier) {
      return unitImpl;
    }
    for (CompilationUnitElement part in _parts) {
      CompilationUnitElementImpl partImpl = part;
      if (partImpl.identifier == identifier) {
        return partImpl;
      }
    }
    for (ImportElement importElement in imports) {
      ImportElementImpl importElementImpl = importElement;
      if (importElementImpl.identifier == identifier) {
        return importElementImpl;
      }
    }
    for (ExportElement exportElement in exports) {
      ExportElementImpl exportElementImpl = exportElement;
      if (exportElementImpl.identifier == identifier) {
        return exportElementImpl;
      }
    }
    return null;
  }

  ClassElement getEnum(String name) {
    ClassElement element = _definingCompilationUnit.getEnum(name);
    if (element != null) {
      return element;
    }
    for (CompilationUnitElement part in _parts) {
      element = part.getEnum(name);
      if (element != null) {
        return element;
      }
    }
    return null;
  }

  @override
  List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) {
    return getImportsWithPrefixFromImports(prefixElement, imports);
  }

  @override
  ClassElement getType(String className) {
    return getTypeFromParts(className, _definingCompilationUnit, _parts);
  }

  /// Given an update to this library which may have added or deleted edges
  /// in the import/export graph originating from this node only, remove any
  /// cached library cycles in the element model which may have been
  /// invalidated.
  void invalidateLibraryCycles() {
    // If we have pre-computed library cycle information, then we must
    // invalidate the information both on this element, and on certain
    // other elements.  Edges originating at this node may have been
    // added or deleted.  A deleted edge that points outside of this cycle
    // cannot change the cycle information for anything outside of this cycle,
    // and so it is sufficient to delete the cached library information on this
    // cycle.  An added edge which points to another node within the cycle
    // only invalidates the cycle.  An added edge which points to a node earlier
    // in the topological sort of cycles induces no invalidation (since there
    // are by definition no back edges from earlier cycles in the topological
    // order, and hence no possible cycle can have been introduced.  The only
    // remaining case is that we have added an edge to a node which is later
    // in the topological sort of cycles.  This can induce cycles, since it
    // represents a new back edge.  It would be sufficient to invalidate the
    // cycle information for all nodes that are between the target and the
    // node in the topological order.  For simplicity, we simply invalidate
    // all nodes which are reachable from the source node.
    // Note that in the invalidation phase, we do not cut off when we encounter
    // a node with no library cycle information, since we do not know whether
    // we are in the case where invalidation has already been performed, or we
    // are in the case where library cycles have simply never been computed from
    // a newly reachable node.
    Set<LibraryElementImpl> active = new HashSet();
    void invalidate(LibraryElement element) {
      LibraryElementImpl library =
          element is LibraryElementHandle ? element.actualElement : element;
      if (active.add(library)) {
        if (library._libraryCycle != null) {
          library._libraryCycle.forEach(invalidate);
          library._libraryCycle = null;
        }
        library.exportedLibraries.forEach(invalidate);
        library.importedLibraries.forEach(invalidate);
      }
    }

    invalidate(this);
  }

  /// Set whether the library has the given [capability] to
  /// correspond to the given [value].
  void setResolutionCapability(
      LibraryResolutionCapability capability, bool value) {
    _resolutionCapabilities =
        BooleanArray.set(_resolutionCapabilities, capability.index, value);
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    _definingCompilationUnit?.accept(visitor);
    safelyVisitChildren(exports, visitor);
    safelyVisitChildren(imports, visitor);
    safelyVisitChildren(_parts, visitor);
  }

  static List<ImportElement> buildImportsFromSummary(LibraryElement library,
      List<UnlinkedImport> unlinkedImports, List<int> importDependencies) {
    int length = unlinkedImports.length;
    if (length != 0) {
      List<ImportElement> imports = new List<ImportElement>();
      for (int i = 0; i < length; i++) {
        int dependency = importDependencies[i];
        ImportElementImpl importElement = new ImportElementImpl.forSerialized(
            unlinkedImports[i], dependency, library);
        imports.add(importElement);
      }
      return imports;
    } else {
      return const <ImportElement>[];
    }
  }

  static List<PrefixElement> buildPrefixesFromImports(
      List<ImportElement> imports) {
    HashSet<PrefixElement> prefixes = new HashSet<PrefixElement>();
    for (ImportElement element in imports) {
      PrefixElement prefix = element.prefix;
      if (prefix != null) {
        prefixes.add(prefix);
      }
    }
    return prefixes.toList(growable: false);
  }

  static FunctionElementImpl createLoadLibraryFunctionForLibrary(
      TypeProvider typeProvider, LibraryElement library) {
    FunctionElementImpl function =
        new FunctionElementImpl(FunctionElement.LOAD_LIBRARY_NAME, -1);
    function.isSynthetic = true;
    function.enclosingElement = library;
    function.returnType = typeProvider.futureDynamicType;
    function.type = new FunctionTypeImpl(function);
    return function;
  }

  /// Return the [LibraryElementImpl] of the given [element].
  static LibraryElementImpl getImpl(LibraryElement element) {
    if (element is LibraryElementHandle) {
      return getImpl(element.actualElement);
    }
    return element as LibraryElementImpl;
  }

  static List<ImportElement> getImportsWithPrefixFromImports(
      PrefixElement prefixElement, List<ImportElement> imports) {
    int count = imports.length;
    List<ImportElement> importList = new List<ImportElement>();
    for (int i = 0; i < count; i++) {
      if (identical(imports[i].prefix, prefixElement)) {
        importList.add(imports[i]);
      }
    }
    return importList;
  }

  static ClassElement getTypeFromParts(
      String className,
      CompilationUnitElement definingCompilationUnit,
      List<CompilationUnitElement> parts) {
    ClassElement type = definingCompilationUnit.getType(className);
    if (type != null) {
      return type;
    }
    for (CompilationUnitElement part in parts) {
      type = part.getType(className);
      if (type != null) {
        return type;
      }
    }
    return null;
  }

  /// Return `true` if the [library] has the given [capability].
  static bool hasResolutionCapability(
      LibraryElement library, LibraryResolutionCapability capability) {
    return library is LibraryElementImpl &&
        BooleanArray.get(library._resolutionCapabilities, capability.index);
  }
}

/// Enum of possible resolution capabilities that a [LibraryElementImpl] has.
enum LibraryResolutionCapability {
  /// All elements have their types resolved.
  resolvedTypeNames,

  /// All (potentially) constants expressions are set into corresponding
  /// elements.
  constantExpressions,
}

/// The context in which the library is resynthesized.
abstract class LibraryResynthesizerContext {
  /// Return the [LinkedLibrary] that corresponds to the library being
  /// resynthesized.
  LinkedLibrary get linkedLibrary;

  /// Return the exported [LibraryElement] for with the given [relativeUri].
  LibraryElement buildExportedLibrary(String relativeUri);

  /// Return the export namespace of the library.
  Namespace buildExportNamespace();

  /// Return the imported [LibraryElement] for the given dependency in the
  /// linked library.
  LibraryElement buildImportedLibrary(int dependency);

  /// Return the public namespace of the library.
  Namespace buildPublicNamespace();

  /// Find the entry point of the library.
  FunctionElement findEntryPoint();

  /// Ensure that getters and setters in different units use the same
  /// top-level variables.
  void patchTopLevelAccessors();
}

/// A concrete implementation of a [LocalVariableElement].
class LocalVariableElementImpl extends NonParameterVariableElementImpl
    implements LocalVariableElement {
  /// The offset to the beginning of the visible range for this element.
  int _visibleRangeOffset = 0;

  /// The length of the visible range for this element, or `-1` if this element
  /// does not have a visible range.
  int _visibleRangeLength = -1;

  /// Initialize a newly created method element to have the given [name] and
  /// [offset].
  LocalVariableElementImpl(String name, int offset) : super(name, offset);

  /// Initialize a newly created local variable element to have the given
  /// [name].
  LocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);

  @override
  String get identifier {
    return '$name$nameOffset';
  }

  @override
  bool get isPotentiallyMutatedInClosure => true;

  @override
  bool get isPotentiallyMutatedInScope => true;

  @override
  ElementKind get kind => ElementKind.LOCAL_VARIABLE;

  @override
  SourceRange get visibleRange {
    if (_visibleRangeLength < 0) {
      return null;
    }
    return new SourceRange(_visibleRangeOffset, _visibleRangeLength);
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitLocalVariableElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write(type);
    buffer.write(" ");
    buffer.write(displayName);
  }

  @deprecated
  @override
  Declaration computeNode() => getNodeMatching(
      (node) => node is DeclaredIdentifier || node is VariableDeclaration);

  /// Set the visible range for this element to the range starting at the given
  /// [offset] with the given [length].
  void setVisibleRange(int offset, int length) {
    _visibleRangeOffset = offset;
    _visibleRangeLength = length;
  }
}

/// A concrete implementation of a [MethodElement].
class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
  /// Initialize a newly created method element to have the given [name] at the
  /// given [offset].
  MethodElementImpl(String name, int offset) : super(name, offset);

  MethodElementImpl.forLinkedNode(Reference reference, LinkedNode linkedNode,
      ClassElementImpl enclosingClass)
      : super.forLinkedNode(enclosingClass, reference, linkedNode);

  /// Initialize a newly created method element to have the given [name].
  MethodElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  MethodElementImpl.forSerialized(
      UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
      : super.forSerialized(serializedExecutable, enclosingClass);

  /// Set whether this method is abstract.
  void set abstract(bool isAbstract) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.ABSTRACT, isAbstract);
  }

  @override
  String get displayName {
    String displayName = super.displayName;
    if ("unary-" == displayName) {
      return "-";
    }
    return displayName;
  }

  @override
  ClassElement get enclosingElement => super.enclosingElement as ClassElement;

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext =>
      super.enclosingElement as ClassElementImpl;

  @override
  bool get isAbstract {
    if (linkedNode != null) {
      return !isExternal && enclosingUnit.linkedContext.isAbstract(linkedNode);
    }
    return super.isAbstract;
  }

  @override
  bool get isOperator {
    String name = displayName;
    if (name.isEmpty) {
      return false;
    }
    int first = name.codeUnitAt(0);
    return !((0x61 <= first && first <= 0x7A) ||
        (0x41 <= first && first <= 0x5A) ||
        first == 0x5F ||
        first == 0x24);
  }

  @override
  bool get isStatic {
    if (linkedNode != null) {
      return linkedNode.methodDeclaration_modifierKeyword != 0;
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isStatic;
    }
    return hasModifier(Modifier.STATIC);
  }

  /// Set whether this method is static.
  void set isStatic(bool isStatic) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.STATIC, isStatic);
  }

  @override
  ElementKind get kind => ElementKind.METHOD;

  @override
  String get name {
    String name = super.name;
    if (name == '-' && parameters.isEmpty) {
      return 'unary-';
    }
    return super.name;
  }

  @override
  DartType get returnType {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getType(
        linkedNode.methodDeclaration_returnType2,
      );
    }
    return super.returnType;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitMethodElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write(displayName);
    super.appendTo(buffer);
  }

  @deprecated
  @override
  MethodDeclaration computeNode() =>
      getNodeMatching((node) => node is MethodDeclaration);

  @deprecated
  @override
  FunctionType getReifiedType(DartType objectType) {
    // TODO(jmesserly): this implementation is completely wrong:
    // It does not handle covariant parameters from a generic class.
    // It drops type parameters from generic methods.
    // Since this method was for DDC, it should be removed.
    //
    // Check whether we have any covariant parameters.
    // Usually we don't, so we can use the same type.
    bool hasCovariant = false;
    for (ParameterElement parameter in parameters) {
      if (parameter.isCovariant) {
        hasCovariant = true;
        break;
      }
    }

    if (!hasCovariant) {
      return type;
    }

    List<ParameterElement> covariantParameters = parameters.map((parameter) {
      DartType type = parameter.isCovariant ? objectType : parameter.type;
      return new ParameterElementImpl.synthetic(
          parameter.name, type, parameter.parameterKind);
    }).toList();

    return new FunctionElementImpl.synthetic(covariantParameters, returnType)
        .type;
  }
}

/// A [ClassElementImpl] representing a mixin declaration.
class MixinElementImpl extends ClassElementImpl {
  // TODO(brianwilkerson) Consider creating an abstract superclass of
  // ClassElementImpl that contains the portions of the API that this class
  // needs, and make this class extend the new class.

  /// A list containing all of the superclass constraints that are defined for
  /// the mixin.
  List<InterfaceType> _superclassConstraints;

  /// Names of methods, getters, setters, and operators that this mixin
  /// declaration super-invokes.  For setters this includes the trailing "=".
  /// The list will be empty if this class is not a mixin declaration.
  List<String> _superInvokedNames;

  /// Initialize a newly created class element to have the given [name] at the
  /// given [offset] in the file that contains the declaration of this element.
  MixinElementImpl(String name, int offset) : super(name, offset);

  /// Initialize a newly created class element to have the given [name].
  MixinElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  MixinElementImpl.forSerialized(
      UnlinkedClass unlinkedClass, CompilationUnitElementImpl enclosingUnit)
      : super.forSerialized(unlinkedClass, enclosingUnit);

  @override
  bool get isAbstract => true;

  @override
  bool get isMixin => true;

  @override
  List<InterfaceType> get superclassConstraints {
    if (_superclassConstraints == null) {
      if (_unlinkedClass != null) {
        List<InterfaceType> constraints;
        if (_unlinkedClass.superclassConstraints.isNotEmpty) {
          ResynthesizerContext context = enclosingUnit.resynthesizerContext;
          constraints = _unlinkedClass.superclassConstraints
              .map((EntityRef t) => context.resolveTypeRef(this, t))
              .where(_isInterfaceTypeInterface)
              .cast<InterfaceType>()
              .toList(growable: false);
        }
        if (constraints == null || constraints.isEmpty) {
          constraints = [context.typeProvider.objectType];
        }
        _superclassConstraints = constraints;
      }
    }
    return _superclassConstraints ?? const <InterfaceType>[];
  }

  void set superclassConstraints(List<InterfaceType> superclassConstraints) {
    _assertNotResynthesized(_unlinkedClass);
    // Note: if we are using  the analysis driver, the set of superclass
    // constraints has already been computed, and it's more accurate. So we
    // only store superclass constraints if we are using the old task model.
    if (_unlinkedClass == null) {
      _superclassConstraints = superclassConstraints;
    }
  }

  @override
  List<String> get superInvokedNames {
    if (_superInvokedNames == null) {
      if (_unlinkedClass != null) {
        _superInvokedNames = _unlinkedClass.superInvokedNames;
      }
    }
    return _superInvokedNames ?? const <String>[];
  }

  void set superInvokedNames(List<String> superInvokedNames) {
    _assertNotResynthesized(_unlinkedClass);
    if (_unlinkedClass == null) {
      _superInvokedNames = superInvokedNames;
    }
  }

  @override
  InterfaceType get supertype => null;

  @override
  void set supertype(InterfaceType supertype) {
    throw new StateError('Attempt to set a supertype for a mixin declaratio.');
  }

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write('mixin ');
    String name = displayName;
    if (name == null) {
      // TODO(brianwilkerson) Can this happen (for either classes or mixins)?
      buffer.write("{unnamed mixin}");
    } else {
      buffer.write(name);
    }
    int variableCount = typeParameters.length;
    if (variableCount > 0) {
      buffer.write("<");
      for (int i = 0; i < variableCount; i++) {
        if (i > 0) {
          buffer.write(", ");
        }
        (typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
      }
      buffer.write(">");
    }
    if (superclassConstraints.isNotEmpty) {
      buffer.write(' on ');
      buffer.write(superclassConstraints.map((t) => t.displayName).join(', '));
    }
    if (interfaces.isNotEmpty) {
      buffer.write(' implements ');
      buffer.write(interfaces.map((t) => t.displayName).join(', '));
    }
  }
}

/// The constants for all of the modifiers defined by the Dart language and for
/// a few additional flags that are useful.
///
/// Clients may not extend, implement or mix-in this class.
class Modifier implements Comparable<Modifier> {
  /// Indicates that the modifier 'abstract' was applied to the element.
  static const Modifier ABSTRACT = const Modifier('ABSTRACT', 0);

  /// Indicates that an executable element has a body marked as being
  /// asynchronous.
  static const Modifier ASYNCHRONOUS = const Modifier('ASYNCHRONOUS', 1);

  /// Indicates that the modifier 'const' was applied to the element.
  static const Modifier CONST = const Modifier('CONST', 2);

  /// Indicates that the modifier 'covariant' was applied to the element.
  static const Modifier COVARIANT = const Modifier('COVARIANT', 3);

  /// Indicates that the import element represents a deferred library.
  static const Modifier DEFERRED = const Modifier('DEFERRED', 4);

  /// Indicates that a class element was defined by an enum declaration.
  static const Modifier ENUM = const Modifier('ENUM', 5);

  /// Indicates that a class element was defined by an enum declaration.
  static const Modifier EXTERNAL = const Modifier('EXTERNAL', 6);

  /// Indicates that the modifier 'factory' was applied to the element.
  static const Modifier FACTORY = const Modifier('FACTORY', 7);

  /// Indicates that the modifier 'final' was applied to the element.
  static const Modifier FINAL = const Modifier('FINAL', 8);

  /// Indicates that an executable element has a body marked as being a
  /// generator.
  static const Modifier GENERATOR = const Modifier('GENERATOR', 9);

  /// Indicates that the pseudo-modifier 'get' was applied to the element.
  static const Modifier GETTER = const Modifier('GETTER', 10);

  /// A flag used for libraries indicating that the defining compilation unit
  /// contains at least one import directive whose URI uses the "dart-ext"
  /// scheme.
  static const Modifier HAS_EXT_URI = const Modifier('HAS_EXT_URI', 11);

  /// Indicates that the associated element did not have an explicit type
  /// associated with it. If the element is an [ExecutableElement], then the
  /// type being referred to is the return type.
  static const Modifier IMPLICIT_TYPE = const Modifier('IMPLICIT_TYPE', 12);

  /// Indicates that a class is a mixin application.
  static const Modifier MIXIN_APPLICATION =
      const Modifier('MIXIN_APPLICATION', 13);

  /// Indicates that a class contains an explicit reference to 'super'.
  static const Modifier REFERENCES_SUPER =
      const Modifier('REFERENCES_SUPER', 14);

  /// Indicates that the pseudo-modifier 'set' was applied to the element.
  static const Modifier SETTER = const Modifier('SETTER', 15);

  /// Indicates that the modifier 'static' was applied to the element.
  static const Modifier STATIC = const Modifier('STATIC', 16);

  /// Indicates that the element does not appear in the source code but was
  /// implicitly created. For example, if a class does not define any
  /// constructors, an implicit zero-argument constructor will be created and it
  /// will be marked as being synthetic.
  static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 17);

  static const List<Modifier> values = const [
    ABSTRACT,
    ASYNCHRONOUS,
    CONST,
    COVARIANT,
    DEFERRED,
    ENUM,
    EXTERNAL,
    FACTORY,
    FINAL,
    GENERATOR,
    GETTER,
    HAS_EXT_URI,
    IMPLICIT_TYPE,
    MIXIN_APPLICATION,
    REFERENCES_SUPER,
    SETTER,
    STATIC,
    SYNTHETIC
  ];

  /// The name of this modifier.
  final String name;

  /// The ordinal value of the modifier.
  final int ordinal;

  const Modifier(this.name, this.ordinal);

  @override
  int get hashCode => ordinal;

  @override
  int compareTo(Modifier other) => ordinal - other.ordinal;

  @override
  String toString() => name;
}

/// A concrete implementation of a [MultiplyDefinedElement].
class MultiplyDefinedElementImpl implements MultiplyDefinedElement {
  /// The unique integer identifier of this element.
  final int id = ElementImpl._NEXT_ID++;

  /// The analysis context in which the multiply defined elements are defined.
  @override
  final AnalysisContext context;

  @override
  final AnalysisSession session;

  /// The name of the conflicting elements.
  @override
  final String name;

  @override
  final List<Element> conflictingElements;

  /// Initialize a newly created element in the given [context] to represent
  /// the given non-empty [conflictingElements].
  MultiplyDefinedElementImpl(
      this.context, this.session, this.name, this.conflictingElements);

  @override
  String get displayName => name;

  @override
  String get documentationComment => null;

  @override
  Element get enclosingElement => null;

  @override
  bool get hasAlwaysThrows => false;

  @override
  bool get hasDeprecated => false;

  @override
  bool get hasFactory => false;

  @override
  bool get hasIsTest => false;

  @override
  bool get hasIsTestGroup => false;

  @override
  bool get hasJS => false;

  @override
  bool get hasLiteral => false;

  @override
  bool get hasOverride => false;

  @override
  bool get hasProtected => false;

  @override
  bool get hasRequired => false;

  @override
  bool get hasSealed => false;

  @override
  bool get hasVisibleForTemplate => false;

  @override
  bool get hasVisibleForTesting => false;

  @override
  bool get isAlwaysThrows => false;

  @override
  bool get isDeprecated => false;

  @override
  bool get isFactory => false;

  @override
  bool get isJS => false;

  @override
  bool get isOverride => false;

  @override
  bool get isPrivate {
    String name = displayName;
    if (name == null) {
      return false;
    }
    return Identifier.isPrivateName(name);
  }

  @override
  bool get isProtected => false;

  @override
  bool get isPublic => !isPrivate;

  @override
  bool get isRequired => false;

  @override
  bool get isSynthetic => true;

  bool get isVisibleForTemplate => false;

  @override
  bool get isVisibleForTesting => false;

  @override
  ElementKind get kind => ElementKind.ERROR;

  @override
  LibraryElement get library => null;

  @override
  Source get librarySource => null;

  @override
  ElementLocation get location => null;

  @override
  List<ElementAnnotation> get metadata => const <ElementAnnotation>[];

  @override
  int get nameLength => displayName != null ? displayName.length : 0;

  @override
  int get nameOffset => -1;

  @override
  Source get source => null;

  @override
  DartType get type => DynamicTypeImpl.instance;

  @override
  CompilationUnit get unit => null;

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitMultiplyDefinedElement(this);

  @override
  String computeDocumentationComment() => null;

  @deprecated
  @override
  AstNode computeNode() => null;

  @override
  E getAncestor<E extends Element>(Predicate<Element> predicate) => null;

  @override
  String getExtendedDisplayName(String shortName) {
    if (shortName != null) {
      return shortName;
    }
    return displayName;
  }

  @override
  bool isAccessibleIn(LibraryElement library) {
    for (Element element in conflictingElements) {
      if (element.isAccessibleIn(library)) {
        return true;
      }
    }
    return false;
  }

  @override
  String toString() {
    StringBuffer buffer = new StringBuffer();
    bool needsSeparator = false;
    void writeList(List<Element> elements) {
      for (Element element in elements) {
        if (needsSeparator) {
          buffer.write(", ");
        } else {
          needsSeparator = true;
        }
        if (element is ElementImpl) {
          element.appendTo(buffer);
        } else {
          buffer.write(element);
        }
      }
    }

    buffer.write("[");
    writeList(conflictingElements);
    buffer.write("]");
    return buffer.toString();
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    // There are no children to visit
  }
}

/// A [MethodElementImpl], with the additional information of a list of
/// [ExecutableElement]s from which this element was composed.
class MultiplyInheritedMethodElementImpl extends MethodElementImpl
    implements MultiplyInheritedExecutableElement {
  /// A list the array of executable elements that were used to compose this
  /// element.
  List<ExecutableElement> _elements = const <MethodElement>[];

  MultiplyInheritedMethodElementImpl(Identifier name) : super.forNode(name) {
    isSynthetic = true;
  }

  @override
  List<ExecutableElement> get inheritedElements => _elements;

  void set inheritedElements(List<ExecutableElement> elements) {
    this._elements = elements;
  }
}

/// A [PropertyAccessorElementImpl], with the additional information of a list
///  of[ExecutableElement]s from which this element was composed.
class MultiplyInheritedPropertyAccessorElementImpl
    extends PropertyAccessorElementImpl
    implements MultiplyInheritedExecutableElement {
  /// A list the array of executable elements that were used to compose this
  /// element.
  List<ExecutableElement> _elements = const <PropertyAccessorElement>[];

  MultiplyInheritedPropertyAccessorElementImpl(Identifier name)
      : super.forNode(name) {
    isSynthetic = true;
  }

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext => null;

  @override
  List<ExecutableElement> get inheritedElements => _elements;

  void set inheritedElements(List<ExecutableElement> elements) {
    this._elements = elements;
  }
}

/// A [VariableElementImpl], which is not a parameter.
abstract class NonParameterVariableElementImpl extends VariableElementImpl {
  /// The unlinked representation of the variable in the summary.
  final UnlinkedVariable _unlinkedVariable;

  /// Initialize a newly created variable element to have the given [name] and
  /// [offset].
  NonParameterVariableElementImpl(String name, int offset)
      : _unlinkedVariable = null,
        super(name, offset);

  NonParameterVariableElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : _unlinkedVariable = null,
        super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created variable element to have the given [name].
  NonParameterVariableElementImpl.forNode(Identifier name)
      : _unlinkedVariable = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  NonParameterVariableElementImpl.forSerialized(
      this._unlinkedVariable, ElementImpl enclosingElement)
      : super.forSerialized(enclosingElement);

  @override
  int get codeLength {
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  String get documentationComment {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getCommentText(
        linkedNode.variableDeclaration_declaration.comment,
      );
    }
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.documentationComment?.text;
    }
    return super.documentationComment;
  }

  @override
  bool get hasImplicitType {
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.type == null;
    }
    return super.hasImplicitType;
  }

  @override
  void set hasImplicitType(bool hasImplicitType) {
    _assertNotResynthesized(_unlinkedVariable);
    super.hasImplicitType = hasImplicitType;
  }

  @override
  FunctionElement get initializer {
    if (_initializer == null) {
      if (_unlinkedVariable != null) {
        UnlinkedExecutable unlinkedInitializer = _unlinkedVariable.initializer;
        if (unlinkedInitializer != null) {
          _initializer =
              new FunctionElementImpl.forSerialized(unlinkedInitializer, this)
                ..isSynthetic = true;
        } else {
          return null;
        }
      }
    }
    return super.initializer;
  }

  /// Set the function representing this variable's initializer to the given
  /// [function].
  void set initializer(FunctionElement function) {
    _assertNotResynthesized(_unlinkedVariable);
    super.initializer = function;
  }

  @override
  bool get isConst {
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.isConst;
    }
    return super.isConst;
  }

  @override
  void set isConst(bool isConst) {
    _assertNotResynthesized(_unlinkedVariable);
    super.isConst = isConst;
  }

  @override
  bool get isFinal {
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.isFinal;
    }
    return super.isFinal;
  }

  @override
  void set isFinal(bool isFinal) {
    _assertNotResynthesized(_unlinkedVariable);
    super.isFinal = isFinal;
  }

  @override
  List<ElementAnnotation> get metadata {
    if (_unlinkedVariable != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, _unlinkedVariable.annotations);
    }
    return super.metadata;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getSimpleName(
        linkedNode.variableDeclaration_name,
      );
    }
    if (_unlinkedVariable != null) {
      return _unlinkedVariable.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getSimpleOffset(
        linkedNode.variableDeclaration_name,
      );
    }
    int offset = super.nameOffset;
    if (offset == 0) {
      if (_unlinkedVariable != null) {
        return _unlinkedVariable.nameOffset;
      }
    }
    return offset;
  }

  @override
  DartType get type {
    if (_unlinkedVariable != null && _declaredType == null && _type == null) {
      _type = enclosingUnit.resynthesizerContext
          .resolveLinkedType(this, _unlinkedVariable.inferredTypeSlot);
      declaredType = enclosingUnit.resynthesizerContext
          .resolveTypeRef(this, _unlinkedVariable.type, declaredType: true);
    }
    return super.type;
  }

  @override
  void set type(DartType type) {
    _assertNotResynthesized(_unlinkedVariable);
    _type = _checkElementOfType(type);
  }

  @override
  TopLevelInferenceError get typeInferenceError {
    if (_unlinkedVariable != null) {
      return enclosingUnit.resynthesizerContext
          .getTypeInferenceError(_unlinkedVariable.inferredTypeSlot);
    }
    // We don't support type inference errors without linking.
    return null;
  }

  /// Subclasses need this getter, see [ConstVariableElement._unlinkedConst].
  UnlinkedExpr get _unlinkedConst => _unlinkedVariable?.initializer?.bodyExpr;
}

/// A concrete implementation of a [ParameterElement].
class ParameterElementImpl extends VariableElementImpl
    with ParameterElementMixin
    implements ParameterElement {
  /// The unlinked representation of the parameter in the summary.
  final UnlinkedParam unlinkedParam;

  /// The kind of this parameter.
  ParameterKind _parameterKind;

  /// The Dart code of the default value.
  String _defaultValueCode;

  /// The offset to the beginning of the visible range for this element.
  int _visibleRangeOffset = 0;

  /// The length of the visible range for this element, or `-1` if this element
  /// does not have a visible range.
  int _visibleRangeLength = -1;

  bool _inheritsCovariant = false;

  /// Initialize a newly created parameter element to have the given [name] and
  /// [nameOffset].
  ParameterElementImpl(String name, int nameOffset)
      : unlinkedParam = null,
        super(name, nameOffset);

  ParameterElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : unlinkedParam = null,
        super.forLinkedNode(enclosing, reference, linkedNode);

  factory ParameterElementImpl.forLinkedNodeFactory(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode) {
    var kind = linkedNode.kind;
    if (kind == LinkedNodeKind.fieldFormalParameter) {
      return FieldFormalParameterElementImpl.forLinkedNode(
        enclosing,
        reference,
        linkedNode,
      );
    } else if (kind == LinkedNodeKind.simpleFormalParameter) {
      return ParameterElementImpl.forLinkedNode(
        enclosing,
        reference,
        linkedNode,
      );
    } else {
      throw UnimplementedError('$kind');
    }
  }

  /// Initialize a newly created parameter element to have the given [name].
  ParameterElementImpl.forNode(Identifier name)
      : unlinkedParam = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  ParameterElementImpl.forSerialized(
      this.unlinkedParam, ElementImpl enclosingElement)
      : super.forSerialized(enclosingElement);

  /// Initialize using the given serialized information.
  factory ParameterElementImpl.forSerializedFactory(
      UnlinkedParam unlinkedParameter, ElementImpl enclosingElement,
      {bool synthetic: false}) {
    ParameterElementImpl element;
    if (unlinkedParameter.isInitializingFormal) {
      if (unlinkedParameter.kind == UnlinkedParamKind.required) {
        element = new FieldFormalParameterElementImpl.forSerialized(
            unlinkedParameter, enclosingElement);
      } else {
        element = new DefaultFieldFormalParameterElementImpl.forSerialized(
            unlinkedParameter, enclosingElement);
      }
    } else {
      if (unlinkedParameter.kind == UnlinkedParamKind.required) {
        element = new ParameterElementImpl.forSerialized(
            unlinkedParameter, enclosingElement);
      } else {
        element = new DefaultParameterElementImpl.forSerialized(
            unlinkedParameter, enclosingElement);
      }
    }
    element.isSynthetic = synthetic;
    return element;
  }

  /// Creates a synthetic parameter with [name], [type] and [kind].
  factory ParameterElementImpl.synthetic(
      String name, DartType type, ParameterKind kind) {
    ParameterElementImpl element = new ParameterElementImpl(name, -1);
    element.type = type;
    element.isSynthetic = true;
    element.parameterKind = kind;
    return element;
  }

  @override
  int get codeLength {
    if (unlinkedParam != null) {
      return unlinkedParam.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (unlinkedParam != null) {
      return unlinkedParam.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  String get defaultValueCode {
    if (unlinkedParam != null) {
      if (unlinkedParam.initializer?.bodyExpr == null) {
        return null;
      }
      return unlinkedParam.defaultValueCode;
    }
    return _defaultValueCode;
  }

  /// Set Dart code of the default value.
  void set defaultValueCode(String defaultValueCode) {
    _assertNotResynthesized(unlinkedParam);
    this._defaultValueCode = StringUtilities.intern(defaultValueCode);
  }

  @override
  bool get hasImplicitType {
    if (unlinkedParam != null) {
      return unlinkedParam.type == null && !unlinkedParam.isFunctionTyped;
    }
    return super.hasImplicitType;
  }

  @override
  void set hasImplicitType(bool hasImplicitType) {
    _assertNotResynthesized(unlinkedParam);
    super.hasImplicitType = hasImplicitType;
  }

  /// True if this parameter inherits from a covariant parameter. This happens
  /// when it overrides a method in a supertype that has a corresponding
  /// covariant parameter.
  bool get inheritsCovariant {
    if (unlinkedParam != null) {
      return enclosingUnit.resynthesizerContext
          .inheritsCovariant(unlinkedParam.inheritsCovariantSlot);
    } else {
      return _inheritsCovariant;
    }
  }

  /// Record whether or not this parameter inherits from a covariant parameter.
  void set inheritsCovariant(bool value) {
    _assertNotResynthesized(unlinkedParam);
    _inheritsCovariant = value;
  }

  @override
  FunctionElement get initializer {
    if (_initializer == null) {
      if (unlinkedParam != null) {
        UnlinkedExecutable unlinkedInitializer = unlinkedParam.initializer;
        if (unlinkedInitializer != null) {
          _initializer =
              new FunctionElementImpl.forSerialized(unlinkedInitializer, this)
                ..isSynthetic = true;
        } else {
          return null;
        }
      }
    }
    return super.initializer;
  }

  /// Set the function representing this variable's initializer to the given
  /// [function].
  void set initializer(FunctionElement function) {
    _assertNotResynthesized(unlinkedParam);
    super.initializer = function;
  }

  @override
  bool get isConst {
    if (unlinkedParam != null) {
      return false;
    }
    return super.isConst;
  }

  @override
  void set isConst(bool isConst) {
    _assertNotResynthesized(unlinkedParam);
    super.isConst = isConst;
  }

  @override
  bool get isCovariant {
    if (linkedNode != null) {
      if (linkedNode.kind == LinkedNodeKind.defaultFormalParameter) {
        var parameter = linkedNode.defaultFormalParameter_parameter;
        return parameter.normalFormalParameter_isCovariant;
      }
      return linkedNode.normalFormalParameter_isCovariant;
    }
    if (isExplicitlyCovariant || inheritsCovariant) {
      return true;
    }
    return false;
  }

  /// Return true if this parameter is explicitly marked as being covariant.
  bool get isExplicitlyCovariant {
    if (unlinkedParam != null) {
      return unlinkedParam.isExplicitlyCovariant;
    }
    return hasModifier(Modifier.COVARIANT);
  }

  /// Set whether this variable parameter is explicitly marked as being
  /// covariant.
  void set isExplicitlyCovariant(bool isCovariant) {
    _assertNotResynthesized(unlinkedParam);
    setModifier(Modifier.COVARIANT, isCovariant);
  }

  @override
  bool get isFinal {
    if (linkedNode != null) {
      if (linkedNode.kind == LinkedNodeKind.defaultFormalParameter) {
        var parameter = linkedNode.defaultFormalParameter_parameter;
        return parameter.simpleFormalParameter_keyword != 0;
      }
      if (linkedNode.kind == LinkedNodeKind.fieldFormalParameter) {
        return false;
      }
      return linkedNode.simpleFormalParameter_keyword != 0;
    }
    if (unlinkedParam != null) {
      return unlinkedParam.isFinal;
    }
    return super.isFinal;
  }

  @override
  void set isFinal(bool isFinal) {
    _assertNotResynthesized(unlinkedParam);
    super.isFinal = isFinal;
  }

  @override
  bool get isInitializingFormal => false;

  @override
  bool get isPotentiallyMutatedInClosure => true;

  @override
  bool get isPotentiallyMutatedInScope => true;

  @override
  ElementKind get kind => ElementKind.PARAMETER;

  @override
  List<ElementAnnotation> get metadata {
    if (unlinkedParam != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, unlinkedParam.annotations);
    }
    return super.metadata;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (unlinkedParam != null) {
      return unlinkedParam.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.getSimpleOffset(
        linkedNode.normalFormalParameter_identifier,
      );
    }

    int offset = super.nameOffset;
    if (offset == 0) {
      if (unlinkedParam != null) {
        if (isSynthetic ||
            (unlinkedParam.name.isEmpty &&
                unlinkedParam.kind != UnlinkedParamKind.named &&
                enclosingElement is GenericFunctionTypeElement)) {
          return -1;
        }
        return unlinkedParam.nameOffset;
      }
    }
    return offset;
  }

  @override
  ParameterKind get parameterKind {
    if (_parameterKind != null) return _parameterKind;

    if (linkedNode != null) {
      if (linkedNode.kind == LinkedNodeKind.defaultFormalParameter) {
        if (linkedNode.defaultFormalParameter_isNamed) {
          return _parameterKind = ParameterKind.NAMED;
        } else {
          return _parameterKind = ParameterKind.POSITIONAL;
        }
      }
      return _parameterKind = ParameterKind.REQUIRED;
    }
    if (unlinkedParam != null) {
      switch (unlinkedParam.kind) {
        case UnlinkedParamKind.named:
          _parameterKind = ParameterKind.NAMED;
          break;
        case UnlinkedParamKind.positional:
          _parameterKind = ParameterKind.POSITIONAL;
          break;
        case UnlinkedParamKind.required:
          _parameterKind = ParameterKind.REQUIRED;
          break;
      }
    }
    return _parameterKind;
  }

  void set parameterKind(ParameterKind parameterKind) {
    _assertNotResynthesized(unlinkedParam);
    _parameterKind = parameterKind;
  }

  @override
  List<ParameterElement> get parameters {
    return const <ParameterElement>[];
  }

  @override
  DartType get type {
    if (linkedNode != null) {
      if (_type != null) return _type;
      if (linkedNode.kind == LinkedNodeKind.defaultFormalParameter) {
        var parameter = linkedNode.defaultFormalParameter_parameter;
        return _type = enclosingUnit.linkedContext.getType(
          parameter.simpleFormalParameter_type2,
        );
      }
      return _type = enclosingUnit.linkedContext.getType(
        linkedNode.simpleFormalParameter_type2,
      );
    }
    _resynthesizeTypeAndParameters();
    return super.type;
  }

  @override
  TopLevelInferenceError get typeInferenceError {
    if (unlinkedParam != null) {
      return enclosingUnit.resynthesizerContext
          .getTypeInferenceError(unlinkedParam.inferredTypeSlot);
    }
    // We don't support type inference errors without linking.
    return null;
  }

  @override
  List<TypeParameterElement> get typeParameters {
    return const <TypeParameterElement>[];
  }

  @override
  SourceRange get visibleRange {
    if (unlinkedParam != null) {
      if (unlinkedParam.visibleLength == 0) {
        return null;
      }
      return new SourceRange(
          unlinkedParam.visibleOffset, unlinkedParam.visibleLength);
    }
    if (_visibleRangeLength < 0) {
      return null;
    }
    return new SourceRange(_visibleRangeOffset, _visibleRangeLength);
  }

  /// Subclasses need this getter, see [ConstVariableElement._unlinkedConst].
  UnlinkedExpr get _unlinkedConst => unlinkedParam?.initializer?.bodyExpr;

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitParameterElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    String left = "";
    String right = "";
    while (true) {
      if (parameterKind == ParameterKind.NAMED) {
        left = "{";
        right = "}";
      } else if (parameterKind == ParameterKind.POSITIONAL) {
        left = "[";
        right = "]";
      } else if (parameterKind == ParameterKind.REQUIRED) {}
      break;
    }
    buffer.write(left);
    appendToWithoutDelimiters(buffer);
    buffer.write(right);
  }

  @deprecated
  @override
  FormalParameter computeNode() =>
      getNodeMatching((node) => node is FormalParameter);

  /// Set the visible range for this element to the range starting at the given
  /// [offset] with the given [length].
  void setVisibleRange(int offset, int length) {
    _assertNotResynthesized(unlinkedParam);
    _visibleRangeOffset = offset;
    _visibleRangeLength = length;
  }

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    safelyVisitChildren(parameters, visitor);
  }

  /// If this element is resynthesized, and its type and parameters have not
  /// been build yet, build them and remember in the corresponding fields.
  void _resynthesizeTypeAndParameters() {
    if (unlinkedParam != null && _declaredType == null && _type == null) {
      if (unlinkedParam.isFunctionTyped) {
        CompilationUnitElementImpl enclosingUnit = this.enclosingUnit;

        var typeElement = new GenericFunctionTypeElementImpl.forOffset(-1);
        typeElement.enclosingElement = this;

        typeElement.parameters = ParameterElementImpl.resynthesizeList(
            unlinkedParam.parameters, typeElement,
            synthetic: isSynthetic);

        typeElement.returnType = enclosingUnit.resynthesizerContext
            .resolveTypeRef(this, unlinkedParam.type);

        _type = new FunctionTypeImpl(typeElement);
        typeElement.type = _type;
      } else {
        if (unlinkedParam.inferredTypeSlot != 0) {
          _type = enclosingUnit.resynthesizerContext
              .resolveLinkedType(this, unlinkedParam.inferredTypeSlot);
        }
        declaredType = enclosingUnit.resynthesizerContext
            .resolveTypeRef(this, unlinkedParam.type, declaredType: true);
      }
    }
  }

  static List<ParameterElement> forLinkedNodeList(
      ElementImpl enclosing,
      LinkedUnitContext context,
      Reference containerRef,
      List<LinkedNode> formalParameters) {
    if (formalParameters == null) {
      return const [];
    }

    return formalParameters.map((node) {
      if (node.kind == LinkedNodeKind.defaultFormalParameter) {
        var parameterNode = node.defaultFormalParameter_parameter;
        var name = context.getFormalParameterName(parameterNode);
        var reference = containerRef.getChild(name);
        reference.node = node;
        return DefaultParameterElementImpl.forLinkedNode(
          enclosing,
          reference,
          node,
        );
      } else {
        var name = context.getFormalParameterName(node);
        var reference = containerRef.getChild(name);
        reference.node = node;
        return ParameterElementImpl.forLinkedNodeFactory(
          enclosing,
          reference,
          node,
        );
      }
    }).toList();
  }

  /// Create and return [ParameterElement]s for the given [unlinkedParameters].
  static List<ParameterElement> resynthesizeList(
      List<UnlinkedParam> unlinkedParameters, ElementImpl enclosingElement,
      {bool synthetic: false}) {
    int length = unlinkedParameters.length;
    if (length != 0) {
      List<ParameterElement> parameters = new List<ParameterElement>(length);
      for (int i = 0; i < length; i++) {
        parameters[i] = new ParameterElementImpl.forSerializedFactory(
            unlinkedParameters[i], enclosingElement,
            synthetic: synthetic);
      }
      return parameters;
    } else {
      return const <ParameterElement>[];
    }
  }
}

/// The parameter of an implicit setter.
class ParameterElementImpl_ofImplicitSetter extends ParameterElementImpl {
  final PropertyAccessorElementImpl_ImplicitSetter setter;

  ParameterElementImpl_ofImplicitSetter(
      PropertyAccessorElementImpl_ImplicitSetter setter)
      : setter = setter,
        super('_${setter.variable.name}', setter.variable.nameOffset) {
    enclosingElement = setter;
    isSynthetic = true;
    parameterKind = ParameterKind.REQUIRED;
  }

  @override
  bool get inheritsCovariant {
    PropertyInducingElement variable = setter.variable;
    if (variable is FieldElementImpl && variable._unlinkedVariable != null) {
      return enclosingUnit.resynthesizerContext
          .inheritsCovariant(variable._unlinkedVariable.inheritsCovariantSlot);
    }
    return super.inheritsCovariant;
  }

  @override
  bool get isCovariant {
    if (isExplicitlyCovariant || inheritsCovariant) {
      return true;
    }
    return false;
  }

  @override
  bool get isExplicitlyCovariant {
    PropertyInducingElement variable = setter.variable;
    if (variable is FieldElementImpl) {
      return variable.isCovariant;
    }
    return false;
  }

  @override
  DartType get type => setter.variable.type;

  @override
  void set type(DartType type) {
    assert(false); // Should never be called.
  }
}

/// A mixin that provides a common implementation for methods defined in
/// [ParameterElement].
mixin ParameterElementMixin implements ParameterElement {
  @override
  bool get isNamed => parameterKind == ParameterKind.NAMED;

  @override
  bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;

  @override
  bool get isOptional =>
      parameterKind == ParameterKind.NAMED ||
      parameterKind == ParameterKind.POSITIONAL;

  @override
  bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;

  @override
  bool get isPositional =>
      parameterKind == ParameterKind.POSITIONAL ||
      parameterKind == ParameterKind.REQUIRED;

  @override
  // Overridden to remove the 'deprecated' annotation.
  ParameterKind get parameterKind;

  @override
  void appendToWithoutDelimiters(StringBuffer buffer) {
    buffer.write(type);
    buffer.write(" ");
    buffer.write(displayName);
    if (defaultValueCode != null) {
      if (parameterKind == ParameterKind.NAMED) {
        buffer.write(": ");
      }
      if (parameterKind == ParameterKind.POSITIONAL) {
        buffer.write(" = ");
      }
      buffer.write(defaultValueCode);
    }
  }
}

/// A concrete implementation of a [PrefixElement].
class PrefixElementImpl extends ElementImpl implements PrefixElement {
  /// The unlinked representation of the import in the summary.
  final UnlinkedImport _unlinkedImport;

  /// Initialize a newly created method element to have the given [name] and
  /// [nameOffset].
  PrefixElementImpl(String name, int nameOffset)
      : _unlinkedImport = null,
        super(name, nameOffset);

  /// Initialize a newly created prefix element to have the given [name].
  PrefixElementImpl.forNode(Identifier name)
      : _unlinkedImport = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  PrefixElementImpl.forSerialized(
      this._unlinkedImport, LibraryElementImpl enclosingLibrary)
      : super.forSerialized(enclosingLibrary);

  @override
  String get displayName => name;

  @override
  LibraryElement get enclosingElement =>
      super.enclosingElement as LibraryElement;

  @override
  String get identifier => "_${super.identifier}";

  @override
  List<LibraryElement> get importedLibraries => const <LibraryElement>[];

  @override
  ElementKind get kind => ElementKind.PREFIX;

  @override
  String get name {
    if (_name == null) {
      if (_unlinkedImport != null) {
        LibraryElementImpl library = enclosingElement as LibraryElementImpl;
        int prefixId = _unlinkedImport.prefixReference;
        return _name = library.unlinkedDefiningUnit.references[prefixId].name;
      }
    }
    return super.name;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedImport != null) {
      return _unlinkedImport.prefixOffset;
    }
    return offset;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) => visitor.visitPrefixElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write("as ");
    super.appendTo(buffer);
  }
}

/// A concrete implementation of a [PropertyAccessorElement].
class PropertyAccessorElementImpl extends ExecutableElementImpl
    implements PropertyAccessorElement {
  /// The variable associated with this accessor.
  PropertyInducingElement variable;

  /// Initialize a newly created property accessor element to have the given
  /// [name] and [offset].
  PropertyAccessorElementImpl(String name, int offset) : super(name, offset);

  PropertyAccessorElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created property accessor element to have the given
  /// [name].
  PropertyAccessorElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  PropertyAccessorElementImpl.forSerialized(
      UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
      : super.forSerialized(serializedExecutable, enclosingElement);

  /// Initialize a newly created synthetic property accessor element to be
  /// associated with the given [variable].
  PropertyAccessorElementImpl.forVariable(PropertyInducingElementImpl variable,
      {Reference reference})
      : super(variable.name, variable.nameOffset, reference: reference) {
    this.variable = variable;
    isStatic = variable.isStatic;
    isSynthetic = true;
  }

  /// Set whether this accessor is abstract.
  void set abstract(bool isAbstract) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.ABSTRACT, isAbstract);
  }

  @override
  PropertyAccessorElement get correspondingGetter {
    if (isGetter || variable == null) {
      return null;
    }
    return variable.getter;
  }

  @override
  PropertyAccessorElement get correspondingSetter {
    if (isSetter || variable == null) {
      return null;
    }
    return variable.setter;
  }

  @override
  String get displayName {
    if (serializedExecutable != null && isSetter) {
      String name = serializedExecutable.name;
      assert(name.endsWith('='));
      return name.substring(0, name.length - 1);
    }
    return super.displayName;
  }

  @override
  TypeParameterizedElementMixin get enclosingTypeParameterContext {
    return (enclosingElement as ElementImpl).typeParameterContext;
  }

  /// Set whether this accessor is a getter.
  void set getter(bool isGetter) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.GETTER, isGetter);
  }

  @override
  String get identifier {
    String name = displayName;
    String suffix = isGetter ? "?" : "=";
    return "$name$suffix";
  }

  @override
  bool get isAbstract {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isAbstract(linkedNode);
    }
    return super.isAbstract;
  }

  @override
  bool get isGetter {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isGetter(linkedNode);
    }
    if (serializedExecutable != null) {
      return serializedExecutable.kind == UnlinkedExecutableKind.getter;
    }
    return hasModifier(Modifier.GETTER);
  }

  @override
  bool get isSetter {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isSetter(linkedNode);
    }
    if (serializedExecutable != null) {
      return serializedExecutable.kind == UnlinkedExecutableKind.setter;
    }
    return hasModifier(Modifier.SETTER);
  }

  @override
  bool get isStatic {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isStatic(linkedNode);
    }
    if (serializedExecutable != null) {
      return serializedExecutable.isStatic ||
          variable is TopLevelVariableElement;
    }
    return hasModifier(Modifier.STATIC);
  }

  /// Set whether this accessor is static.
  void set isStatic(bool isStatic) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.STATIC, isStatic);
  }

  @override
  ElementKind get kind {
    if (isGetter) {
      return ElementKind.GETTER;
    }
    return ElementKind.SETTER;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (serializedExecutable != null) {
      return serializedExecutable.name;
    }
    if (isSetter) {
      return "${super.name}=";
    }
    return super.name;
  }

  /// Set whether this accessor is a setter.
  void set setter(bool isSetter) {
    _assertNotResynthesized(serializedExecutable);
    setModifier(Modifier.SETTER, isSetter);
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitPropertyAccessorElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write(isGetter ? "get " : "set ");
    buffer.write(variable.displayName);
    super.appendTo(buffer);
  }

  @deprecated
  @override
  AstNode computeNode() {
    if (isSynthetic) {
      return null;
    }
    if (enclosingElement is ClassElement) {
      return getNodeMatching((node) => node is MethodDeclaration);
    } else if (enclosingElement is CompilationUnitElement) {
      return getNodeMatching((node) => node is FunctionDeclaration);
    }
    return null;
  }
}

/// Implicit getter for a [PropertyInducingElementImpl].
class PropertyAccessorElementImpl_ImplicitGetter
    extends PropertyAccessorElementImpl {
  /// Create the implicit getter and bind it to the [property].
  PropertyAccessorElementImpl_ImplicitGetter(
      PropertyInducingElementImpl property,
      {Reference reference})
      : super.forVariable(property, reference: reference) {
    property.getter = this;
    enclosingElement = property.enclosingElement;
  }

  @override
  bool get hasImplicitReturnType => variable.hasImplicitType;

  @override
  bool get isGetter => true;

  @override
  DartType get returnType => variable.type;

  @override
  void set returnType(DartType returnType) {
    assert(false); // Should never be called.
  }

  @override
  FunctionType get type {
    return _type ??= new FunctionTypeImpl(this);
  }

  @override
  void set type(FunctionType type) {
    assert(false); // Should never be called.
  }
}

/// Implicit setter for a [PropertyInducingElementImpl].
class PropertyAccessorElementImpl_ImplicitSetter
    extends PropertyAccessorElementImpl {
  /// Create the implicit setter and bind it to the [property].
  PropertyAccessorElementImpl_ImplicitSetter(
      PropertyInducingElementImpl property,
      {Reference reference})
      : super.forVariable(property, reference: reference) {
    property.setter = this;
    enclosingElement = property.enclosingElement;
  }

  @override
  bool get isSetter => true;

  @override
  List<ParameterElement> get parameters {
    return _parameters ??= <ParameterElement>[
      new ParameterElementImpl_ofImplicitSetter(this)
    ];
  }

  @override
  DartType get returnType => VoidTypeImpl.instance;

  @override
  void set returnType(DartType returnType) {
    assert(false); // Should never be called.
  }

  @override
  FunctionType get type {
    return _type ??= new FunctionTypeImpl(this);
  }

  @override
  void set type(FunctionType type) {
    assert(false); // Should never be called.
  }
}

/// A concrete implementation of a [PropertyInducingElement].
abstract class PropertyInducingElementImpl
    extends NonParameterVariableElementImpl implements PropertyInducingElement {
  /// The getter associated with this element.
  PropertyAccessorElement getter;

  /// The setter associated with this element, or `null` if the element is
  /// effectively `final` and therefore does not have a setter associated with
  /// it.
  PropertyAccessorElement setter;

  /// Initialize a newly created synthetic element to have the given [name] and
  /// [offset].
  PropertyInducingElementImpl(String name, int offset) : super(name, offset);

  PropertyInducingElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created element to have the given [name].
  PropertyInducingElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  PropertyInducingElementImpl.forSerialized(
      UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedVariable, enclosingElement);

  @override
  bool get isConstantEvaluated => true;

  @deprecated
  @override
  DartType get propagatedType => null;

  @deprecated
  void set propagatedType(DartType propagatedType) {}

  @override
  DartType get type {
    if (linkedNode != null) {
      if (_type != null) return _type;
      return _type = enclosingUnit.linkedContext.getType(
        linkedNode.variableDeclaration_type2,
      );
    }
    if (isSynthetic && _type == null) {
      if (getter != null) {
        _type = getter.returnType;
      } else if (setter != null) {
        List<ParameterElement> parameters = setter.parameters;
        _type = parameters.isNotEmpty
            ? parameters[0].type
            : DynamicTypeImpl.instance;
      } else {
        _type = DynamicTypeImpl.instance;
      }
    }
    return super.type;
  }
}

/// The context in which elements are resynthesized.
abstract class ResynthesizerContext {
  @deprecated
  bool get isStrongMode;

  /// Build [ElementAnnotationImpl] for the given [UnlinkedExpr].
  ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc);

  /// Build [Expression] for the given [UnlinkedExpr].
  Expression buildExpression(ElementImpl context, UnlinkedExpr uc);

  /// Build explicit top-level property accessors.
  UnitExplicitTopLevelAccessors buildTopLevelAccessors();

  /// Build explicit top-level variables.
  UnitExplicitTopLevelVariables buildTopLevelVariables();

  /// Return the error reported during type inference for the given [slot],
  /// or `null` if there was no error.
  TopLevelInferenceError getTypeInferenceError(int slot);

  /// Return `true` if the given parameter [slot] inherits `@covariant`
  /// behavior.
  bool inheritsCovariant(int slot);

  /// Return `true` if the given const constructor [slot] is a part of a cycle.
  bool isInConstCycle(int slot);

  bool isSimplyBounded(int notSimplyBoundedSlot);

  /// Resolve an [EntityRef] into a constructor.  If the reference is
  /// unresolved, return `null`.
  ConstructorElement resolveConstructorRef(
      ElementImpl context, EntityRef entry);

  /// Build the appropriate [DartType] object corresponding to a slot id in the
  /// [LinkedUnit.types] table.
  DartType resolveLinkedType(ElementImpl context, int slot);

  /// Resolve an [EntityRef] into a type.  If the reference is
  /// unresolved, return [DynamicTypeImpl.instance].
  ///
  /// TODO(paulberry): or should we have a class representing an
  /// unresolved type, for consistency with the full element model?
  DartType resolveTypeRef(ElementImpl context, EntityRef type,
      {bool defaultVoid: false,
      bool instantiateToBoundsAllowed: true,
      bool declaredType: false});
}

/// A concrete implementation of a [ShowElementCombinator].
class ShowElementCombinatorImpl implements ShowElementCombinator {
  /// The unlinked representation of the combinator in the summary.
  final UnlinkedCombinator _unlinkedCombinator;

  /// The names that are to be made visible in the importing library if they are
  /// defined in the imported library.
  List<String> _shownNames;

  /// The offset of the character immediately following the last character of
  /// this node.
  int _end = -1;

  /// The offset of the 'show' keyword of this element.
  int _offset = 0;

  ShowElementCombinatorImpl() : _unlinkedCombinator = null;

  /// Initialize using the given serialized information.
  ShowElementCombinatorImpl.forSerialized(this._unlinkedCombinator);

  @override
  int get end {
    if (_unlinkedCombinator != null) {
      return _unlinkedCombinator.end;
    }
    return _end;
  }

  void set end(int end) {
    _assertNotResynthesized(_unlinkedCombinator);
    _end = end;
  }

  @override
  int get offset {
    if (_unlinkedCombinator != null) {
      return _unlinkedCombinator.offset;
    }
    return _offset;
  }

  void set offset(int offset) {
    _assertNotResynthesized(_unlinkedCombinator);
    _offset = offset;
  }

  @override
  List<String> get shownNames {
    if (_unlinkedCombinator != null) {
      _shownNames ??= _unlinkedCombinator.shows.toList(growable: false);
    }
    return _shownNames ?? const <String>[];
  }

  void set shownNames(List<String> shownNames) {
    _assertNotResynthesized(_unlinkedCombinator);
    _shownNames = shownNames;
  }

  @override
  String toString() {
    StringBuffer buffer = new StringBuffer();
    buffer.write("show ");
    int count = shownNames.length;
    for (int i = 0; i < count; i++) {
      if (i > 0) {
        buffer.write(", ");
      }
      buffer.write(shownNames[i]);
    }
    return buffer.toString();
  }
}

/// Mixin providing the implementation of
/// [TypeParameterizedElement.isSimplyBounded] for elements that define a type.
mixin SimplyBoundableMixin implements TypeParameterizedElement {
  CompilationUnitElementImpl get enclosingUnit;

  @override
  bool get isSimplyBounded {
    var notSimplyBoundedSlot = _notSimplyBoundedSlot;
    if (notSimplyBoundedSlot == null) {
      // No summary is in use; we must be on the old task model.  Not supported.
      // TODO(paulberry): remove this check when the old task model is gone.
      return true;
    }
    if (notSimplyBoundedSlot == 0) {
      return true;
    }
    return enclosingUnit.resynthesizerContext
        .isSimplyBounded(_notSimplyBoundedSlot);
  }

  int get _notSimplyBoundedSlot;
}

/// A concrete implementation of a [TopLevelVariableElement].
class TopLevelVariableElementImpl extends PropertyInducingElementImpl
    implements TopLevelVariableElement {
  /// Initialize a newly created synthetic top-level variable element to have
  /// the given [name] and [offset].
  TopLevelVariableElementImpl(String name, int offset) : super(name, offset);

  TopLevelVariableElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode) {
    if (!linkedNode.isSynthetic) {
      var enclosingRef = enclosing.reference;

      this.getter = PropertyAccessorElementImpl_ImplicitGetter(
        this,
        reference: enclosingRef.getChild('@getter').getChild(name),
      );

      if (!isConst && !isFinal) {
        this.setter = PropertyAccessorElementImpl_ImplicitSetter(
          this,
          reference: enclosingRef.getChild('@setter').getChild(name),
        );
      }
    }
  }

  factory TopLevelVariableElementImpl.forLinkedNodeFactory(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode) {
    if (enclosing.enclosingUnit.linkedContext.isConst(linkedNode)) {
      return ConstTopLevelVariableElementImpl.forLinkedNode(
        enclosing,
        reference,
        linkedNode,
      );
    }
    return TopLevelVariableElementImpl.forLinkedNode(
      enclosing,
      reference,
      linkedNode,
    );
  }

  /// Initialize a newly created top-level variable element to have the given
  /// [name].
  TopLevelVariableElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  TopLevelVariableElementImpl.forSerialized(
      UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
      : super.forSerialized(unlinkedVariable, enclosingElement);

  @override
  bool get isStatic => true;

  @override
  ElementKind get kind => ElementKind.TOP_LEVEL_VARIABLE;

  UnlinkedVariable get unlinkedVariableForTesting => _unlinkedVariable;

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitTopLevelVariableElement(this);

  @deprecated
  @override
  VariableDeclaration computeNode() =>
      getNodeMatching((node) => node is VariableDeclaration);
}

/// A concrete implementation of a [TypeParameterElement].
class TypeParameterElementImpl extends ElementImpl
    implements TypeParameterElement {
  /// The unlinked representation of the type parameter in the summary.
  final UnlinkedTypeParam _unlinkedTypeParam;

  /// The type defined by this type parameter.
  TypeParameterType _type;

  /// The type representing the bound associated with this parameter, or `null`
  /// if this parameter does not have an explicit bound.
  DartType _bound;

  /// Initialize a newly created method element to have the given [name] and
  /// [offset].
  TypeParameterElementImpl(String name, int offset)
      : _unlinkedTypeParam = null,
        super(name, offset);

  TypeParameterElementImpl.forLinkedNode(
      TypeParameterizedElementMixin enclosing,
      Reference reference,
      LinkedNode linkedNode)
      : _unlinkedTypeParam = null,
        super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created type parameter element to have the given
  /// [name].
  TypeParameterElementImpl.forNode(Identifier name)
      : _unlinkedTypeParam = null,
        super.forNode(name);

  /// Initialize using the given serialized information.
  TypeParameterElementImpl.forSerialized(
      this._unlinkedTypeParam, TypeParameterizedElementMixin enclosingElement)
      : super.forSerialized(enclosingElement);

  /// Initialize a newly created synthetic type parameter element to have the
  /// given [name], and with [synthetic] set to true.
  TypeParameterElementImpl.synthetic(String name)
      : _unlinkedTypeParam = null,
        super(name, -1) {
    isSynthetic = true;
  }

  DartType get bound {
    if (_bound != null) return _bound;

    if (linkedNode != null) {
      var bound = linkedNode.typeParameter_bound;
      if (bound != null) {
        var context = enclosingUnit.linkedContext;
        return _bound = context.getTypeAnnotationType(bound);
      } else {
        return null;
      }
    }

    if (_unlinkedTypeParam != null) {
      if (_unlinkedTypeParam.bound == null) {
        return null;
      }
      return _bound = enclosingUnit.resynthesizerContext.resolveTypeRef(
          this, _unlinkedTypeParam.bound,
          instantiateToBoundsAllowed: false, declaredType: true);
    }

    return _bound;
  }

  void set bound(DartType bound) {
    _assertNotResynthesized(_unlinkedTypeParam);
    _bound = _checkElementOfType(bound);
  }

  @override
  int get codeLength {
    if (_unlinkedTypeParam != null) {
      return _unlinkedTypeParam.codeRange?.length;
    }
    return super.codeLength;
  }

  @override
  int get codeOffset {
    if (_unlinkedTypeParam != null) {
      return _unlinkedTypeParam.codeRange?.offset;
    }
    return super.codeOffset;
  }

  @override
  String get displayName => name;

  @override
  ElementKind get kind => ElementKind.TYPE_PARAMETER;

  @override
  List<ElementAnnotation> get metadata {
    if (_unlinkedTypeParam != null) {
      return _metadata ??=
          _buildAnnotations(enclosingUnit, _unlinkedTypeParam.annotations);
    }
    return super.metadata;
  }

  @override
  String get name {
    if (linkedNode != null) {
      return reference.name;
    }
    if (_unlinkedTypeParam != null) {
      return _unlinkedTypeParam.name;
    }
    return super.name;
  }

  @override
  int get nameOffset {
    int offset = super.nameOffset;
    if (offset == 0 && _unlinkedTypeParam != null) {
      return _unlinkedTypeParam.nameOffset;
    }
    return offset;
  }

  TypeParameterType get type {
    if (linkedNode != null) {
      _type ??= new TypeParameterTypeImpl(this);
    }
    if (_unlinkedTypeParam != null) {
      _type ??= new TypeParameterTypeImpl(this);
    }
    return _type;
  }

  void set type(TypeParameterType type) {
    _type = type;
  }

  @override
  T accept<T>(ElementVisitor<T> visitor) =>
      visitor.visitTypeParameterElement(this);

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write(displayName);
    if (bound != null) {
      buffer.write(" extends ");
      buffer.write(bound);
    }
  }
}

/// Mixin representing an element which can have type parameters.
mixin TypeParameterizedElementMixin
    implements
        TypeParameterizedElement,
        ElementImpl,
        TypeParameterSerializationContext {
  /// A cached list containing the type parameters declared by this element
  /// directly, or `null` if the elements have not been created yet. This does
  /// not include type parameters that are declared by any enclosing elements.
  List<TypeParameterElement> _typeParameterElements;

  /// A cached list containing the type parameter types declared by this element
  /// directly, or `null` if the list has not been computed yet.
  List<TypeParameterType> _typeParameterTypes;

  /// Get the type parameter context enclosing this one, if any.
  TypeParameterizedElementMixin get enclosingTypeParameterContext;

  @override
  bool get isSimplyBounded => true;

  @override
  TypeParameterizedElementMixin get typeParameterContext => this;

  @override
  List<TypeParameterElement> get typeParameters {
    if (_typeParameterElements != null) return _typeParameterElements;

    if (linkedNode != null) {
      var context = enclosingUnit.linkedContext;
      var containerRef = reference.getChild('@typeParameter');
      var typeParameters = context.getTypeParameters(linkedNode);
      if (typeParameters == null) {
        return _typeParameterElements = const [];
      }
      return _typeParameterElements = typeParameters.map((node) {
        var name = context.getSimpleName(node.typeParameter_name);
        var reference = containerRef.getChild(name);
        reference.node = node;
        return TypeParameterElementImpl.forLinkedNode(this, reference, node);
      }).toList();
    }

    List<UnlinkedTypeParam> unlinkedParams = unlinkedTypeParams;
    if (unlinkedParams != null) {
      int numTypeParameters = unlinkedParams.length;
      _typeParameterElements =
          new List<TypeParameterElement>(numTypeParameters);
      for (int i = 0; i < numTypeParameters; i++) {
        _typeParameterElements[i] =
            new TypeParameterElementImpl.forSerialized(unlinkedParams[i], this);
      }
    }

    return _typeParameterElements ?? const <TypeParameterElement>[];
  }

  /// Get a list of [TypeParameterType] objects corresponding to the
  /// element's type parameters.
  List<TypeParameterType> get typeParameterTypes {
    return _typeParameterTypes ??= typeParameters
        .map((TypeParameterElement e) => e.type)
        .toList(growable: false);
  }

  /// Get the [UnlinkedTypeParam]s representing the type parameters declared by
  /// this element, or `null` if this element isn't from a summary.
  ///
  /// TODO(scheglov) make private after switching linker to Impl
  List<UnlinkedTypeParam> get unlinkedTypeParams;

  @override
  int computeDeBruijnIndex(TypeParameterElement typeParameter,
      {int offset = 0}) {
    if (typeParameter.enclosingElement == this) {
      var index = typeParameters.indexOf(typeParameter);
      assert(index >= 0);
      return typeParameters.length - index + offset;
    } else if (enclosingTypeParameterContext != null) {
      return enclosingTypeParameterContext.computeDeBruijnIndex(typeParameter,
          offset: offset + typeParameters.length);
    } else {
      return null;
    }
  }

  /// Convert the given [index] into a type parameter type.
  TypeParameterType getTypeParameterType(int index) {
    List<TypeParameterType> types = typeParameterTypes;
    if (index <= types.length) {
      return types[types.length - index];
    } else if (enclosingTypeParameterContext != null) {
      return enclosingTypeParameterContext
          .getTypeParameterType(index - types.length);
    } else {
      // If we get here, it means that a summary contained a type parameter
      // index that was out of range.
      throw new RangeError('Invalid type parameter index');
    }
  }
}

/// Interface used by linker serialization methods to convert type parameter
/// references into De Bruijn indices.
abstract class TypeParameterSerializationContext {
  /// Return the given [typeParameter]'s de Bruijn index in this context, or
  /// `null` if it's not in scope.
  ///
  /// If an [offset] is provided, then it is added to the computed index.
  int computeDeBruijnIndex(TypeParameterElement typeParameter, {int offset: 0});
}

/// Container with information about explicit top-level property accessors and
/// corresponding implicit top-level variables.
class UnitExplicitTopLevelAccessors {
  final List<PropertyAccessorElementImpl> accessors =
      <PropertyAccessorElementImpl>[];
  final List<TopLevelVariableElementImpl> implicitVariables =
      <TopLevelVariableElementImpl>[];
}

/// Container with information about explicit top-level variables and
/// corresponding implicit top-level property accessors.
class UnitExplicitTopLevelVariables {
  final List<TopLevelVariableElementImpl> variables;
  final List<PropertyAccessorElementImpl> implicitAccessors =
      <PropertyAccessorElementImpl>[];

  UnitExplicitTopLevelVariables(int numberOfVariables)
      : variables = numberOfVariables != 0
            ? new List<TopLevelVariableElementImpl>(numberOfVariables)
            : const <TopLevelVariableElementImpl>[];
}

/// A concrete implementation of a [UriReferencedElement].
abstract class UriReferencedElementImpl extends ElementImpl
    implements UriReferencedElement {
  /// The offset of the URI in the file, or `-1` if this node is synthetic.
  int _uriOffset = -1;

  /// The offset of the character immediately following the last character of
  /// this node's URI, or `-1` if this node is synthetic.
  int _uriEnd = -1;

  /// The URI that is specified by this directive.
  String _uri;

  /// Initialize a newly created import element to have the given [name] and
  /// [offset]. The offset may be `-1` if the element is synthetic.
  UriReferencedElementImpl(String name, int offset) : super(name, offset);

  UriReferencedElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize using the given serialized information.
  UriReferencedElementImpl.forSerialized(ElementImpl enclosingElement)
      : super.forSerialized(enclosingElement);

  /// Return the URI that is specified by this directive.
  String get uri => _uri;

  /// Set the URI that is specified by this directive to be the given [uri].
  void set uri(String uri) {
    _uri = uri;
  }

  /// Return the offset of the character immediately following the last
  /// character of this node's URI, or `-1` if this node is synthetic.
  int get uriEnd => _uriEnd;

  /// Set the offset of the character immediately following the last character
  /// of this node's URI to the given [offset].
  void set uriEnd(int offset) {
    _uriEnd = offset;
  }

  /// Return the offset of the URI in the file, or `-1` if this node is
  /// synthetic.
  int get uriOffset => _uriOffset;

  /// Set the offset of the URI in the file to the given [offset].
  void set uriOffset(int offset) {
    _uriOffset = offset;
  }

  String _selectUri(
      String defaultUri, List<UnlinkedConfiguration> configurations) {
    for (UnlinkedConfiguration configuration in configurations) {
      if (context.declaredVariables.get(configuration.name) ==
          configuration.value) {
        return configuration.uri;
      }
    }
    return defaultUri;
  }
}

/// A concrete implementation of a [VariableElement].
abstract class VariableElementImpl extends ElementImpl
    implements VariableElement {
  /// The declared type of this variable.
  DartType _declaredType;

  /// The inferred type of this variable.
  DartType _type;

  /// A synthetic function representing this variable's initializer, or `null
  ///` if this variable does not have an initializer.
  FunctionElement _initializer;

  /// Initialize a newly created variable element to have the given [name] and
  /// [offset].
  VariableElementImpl(String name, int offset) : super(name, offset);

  VariableElementImpl.forLinkedNode(
      ElementImpl enclosing, Reference reference, LinkedNode linkedNode)
      : super.forLinkedNode(enclosing, reference, linkedNode);

  /// Initialize a newly created variable element to have the given [name].
  VariableElementImpl.forNode(Identifier name) : super.forNode(name);

  /// Initialize using the given serialized information.
  VariableElementImpl.forSerialized(ElementImpl enclosingElement)
      : super.forSerialized(enclosingElement);

  /// If this element represents a constant variable, and it has an initializer,
  /// a copy of the initializer for the constant.  Otherwise `null`.
  ///
  /// Note that in correct Dart code, all constant variables must have
  /// initializers.  However, analyzer also needs to handle incorrect Dart code,
  /// in which case there might be some constant variables that lack
  /// initializers.
  Expression get constantInitializer => null;

  @override
  DartObject get constantValue => evaluationResult?.value;

  void set declaredType(DartType type) {
    if (linkedNode != null) {
      enclosingUnit.linkedContext.setVariableType(linkedNode, type);
    }
    _declaredType = _checkElementOfType(type);
  }

  @override
  String get displayName => name;

  /// Return the result of evaluating this variable's initializer as a
  /// compile-time constant expression, or `null` if this variable is not a
  /// 'const' variable, if it does not have an initializer, or if the
  /// compilation unit containing the variable has not been resolved.
  EvaluationResultImpl get evaluationResult => null;

  /// Set the result of evaluating this variable's initializer as a compile-time
  /// constant expression to the given [result].
  void set evaluationResult(EvaluationResultImpl result) {
    throw new StateError(
        "Invalid attempt to set a compile-time constant result");
  }

  @override
  bool get hasImplicitType {
    return hasModifier(Modifier.IMPLICIT_TYPE);
  }

  /// Set whether this variable element has an implicit type.
  void set hasImplicitType(bool hasImplicitType) {
    setModifier(Modifier.IMPLICIT_TYPE, hasImplicitType);
  }

  @override
  FunctionElement get initializer => _initializer;

  /// Set the function representing this variable's initializer to the given
  /// [function].
  void set initializer(FunctionElement function) {
    if (function != null) {
      (function as FunctionElementImpl).enclosingElement = this;
    }
    this._initializer = function;
  }

  @override
  bool get isConst {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isConst(linkedNode);
    }
    return hasModifier(Modifier.CONST);
  }

  /// Set whether this variable is const.
  void set isConst(bool isConst) {
    setModifier(Modifier.CONST, isConst);
  }

  @override
  bool get isConstantEvaluated => true;

  @override
  bool get isFinal {
    if (linkedNode != null) {
      return enclosingUnit.linkedContext.isFinal(linkedNode);
    }
    return hasModifier(Modifier.FINAL);
  }

  /// Set whether this variable is final.
  void set isFinal(bool isFinal) {
    setModifier(Modifier.FINAL, isFinal);
  }

  @override
  bool get isPotentiallyMutatedInClosure => false;

  @override
  bool get isPotentiallyMutatedInScope => false;

  @override
  bool get isStatic => hasModifier(Modifier.STATIC);

  @override
  DartType get type => _type ?? _declaredType;

  void set type(DartType type) {
    _type = _checkElementOfType(type);
  }

  /// Return the error reported during type inference for this variable, or
  /// `null` if this variable is not a subject of type inference, or there was
  /// no error.
  TopLevelInferenceError get typeInferenceError {
    return null;
  }

  @override
  void appendTo(StringBuffer buffer) {
    buffer.write(type);
    buffer.write(" ");
    buffer.write(displayName);
  }

  @override
  DartObject computeConstantValue() => null;

  @override
  void visitChildren(ElementVisitor visitor) {
    super.visitChildren(visitor);
    _initializer?.accept(visitor);
  }
}
