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

import 'dart:async';
import 'dart:convert';
import 'dart:io' as io;

import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:kernel/application_root.dart';
import 'package:package_config/discovery.dart';
import 'package:package_config/packages.dart';

import 'package:kernel/ast.dart' as ast;
import 'package:kernel/target/targets.dart' show Target;
import 'package:kernel/type_algebra.dart';
import 'package:analyzer/src/kernel/ast_from_analyzer.dart';

/// Options passed to the Dart frontend.
class DartOptions {
  /// True if user code should be loaded in strong mode.
  bool strongMode;

  /// True if the Dart SDK should be loaded in strong mode.
  bool strongModeSdk;

  /// Path to the sdk sources, ignored if sdkSummary is provided.
  String sdk;

  /// Path to a summary of the sdk sources.
  String sdkSummary;

  /// Path to the `.packages` file.
  String packagePath;

  /// Root used to relativize app file-urls, making them machine agnostic.
  ApplicationRoot applicationRoot;

  Map<Uri, Uri> customUriMappings;

  /// Environment definitions provided via `-Dkey=value`.
  Map<String, String> declaredVariables;

  DartOptions(
      {bool strongMode: false,
      bool strongModeSdk,
      this.sdk,
      this.sdkSummary,
      this.packagePath,
      ApplicationRoot applicationRoot,
      Map<Uri, Uri> customUriMappings,
      Map<String, String> declaredVariables})
      : this.customUriMappings = customUriMappings ?? <Uri, Uri>{},
        this.declaredVariables = declaredVariables ?? <String, String>{},
        this.strongMode = strongMode,
        this.strongModeSdk = strongModeSdk ?? strongMode,
        this.applicationRoot = applicationRoot ?? new ApplicationRoot.none();
}

abstract class ReferenceLevelLoader {
  ast.Library getLibraryReference(LibraryElement element);
  ast.Class getClassReference(ClassElement element);
  ast.Member getMemberReference(Element element);
  ast.Class getRootClassReference();
  ast.Constructor getRootClassConstructorReference();
  ast.Class getCoreClassReference(String className);
  ast.Constructor getCoreClassConstructorReference(String className,
      {String constructorName, String library});
  ast.TypeParameter tryGetClassTypeParameter(TypeParameterElement element);
  ast.Class getSharedMixinApplicationClass(
      ast.Library library, ast.Class supertype, ast.Class mixin);
  bool get strongMode;

  /// Whether or not to include redirecting factories in the output.
  bool get ignoreRedirectingFactories;
}

class DartLoader implements ReferenceLevelLoader {
  final ast.Program program;
  final ApplicationRoot applicationRoot;
  final Bimap<ClassElement, ast.Class> _classes =
      new Bimap<ClassElement, ast.Class>();
  final Bimap<Element, ast.Member> _members = new Bimap<Element, ast.Member>();
  final Map<TypeParameterElement, ast.TypeParameter> _classTypeParameters =
      <TypeParameterElement, ast.TypeParameter>{};
  final Map<ast.Library, Map<String, ast.Class>> _mixinApplications =
      <ast.Library, Map<String, ast.Class>>{};
  final Map<LibraryElement, ast.Library> _libraries =
      <LibraryElement, ast.Library>{};
  final AnalysisContext context;
  LibraryElement _dartCoreLibrary;
  final List errors = [];
  final List libraryElements = [];

  /// Classes that have been referenced, and must be promoted to type level
  /// so as not to expose partially initialized classes.
  final List<ast.Class> temporaryClassWorklist = [];

  final Map<LibraryElement, List<ClassElement>> mixinLibraryWorklist = {};

  final bool ignoreRedirectingFactories;

  LibraryElement _libraryBeingLoaded = null;
  ClassElement _classBeingPromotedToMixin = null;

  bool get strongMode => context.analysisOptions.strongMode;

  DartLoader(this.program, DartOptions options, Packages packages,
      {DartSdk dartSdk,
      AnalysisContext context,
      this.ignoreRedirectingFactories: true})
      : this.context =
            context ?? createContext(options, packages, dartSdk: dartSdk),
        this.applicationRoot = options.applicationRoot;

  String getLibraryName(LibraryElement element) {
    return element.name.isEmpty ? null : element.name;
  }

  LibraryElement getLibraryElementFromUri(Uri uri) {
    var source = context.sourceFactory.forUri2(uri);
    if (source == null) return null;
    return context.computeLibraryElement(source);
  }

  ast.Library getLibraryReference(LibraryElement element) {
    var uri = applicationRoot.relativeUri(element.source.uri);
    var library = _libraries[element];
    if (library == null) {
      library = new ast.Library(uri)
        ..isExternal = true
        ..name = getLibraryName(element)
        ..fileUri = '${element.source.uri}';
      program.libraries.add(library..parent = program);
      _libraries[element] = library;
    }
    return library;
  }

  ast.Library getLibraryReferenceFromUri(Uri uri) {
    return getLibraryReference(getLibraryElementFromUri(uri));
  }

  void _buildTopLevelMember(
      ast.Member member, Element element, Declaration astNode) {
    assert(member.parent != null);
    new MemberBodyBuilder(this, member, element).build(astNode);
  }

  /// True if [element] is in the process of being loaded by
  /// [_buildLibraryBody].
  ///
  /// If this is the case, we should avoid adding new members to the classes
  /// in the library, since the AST builder will rebuild the member lists.
  bool isLibraryBeingLoaded(LibraryElement element) {
    return _libraryBeingLoaded == element;
  }

  bool isClassBeingPromotedToMixin(ClassElement element) {
    return _classBeingPromotedToMixin == element;
  }

  void _buildLibraryBody(LibraryElement element, ast.Library library,
      List<CompilationUnit> units) {
    assert(_libraryBeingLoaded == null);
    _libraryBeingLoaded = element;
    var classes = <ast.Class>[];
    var procedures = <ast.Procedure>[];
    var fields = <ast.Field>[];

    void loadClass(NamedCompilationUnitMember declaration) {
      // [declaration] can be a ClassDeclaration, EnumDeclaration, or a
      // ClassTypeAlias.
      ClassElement element = declaration.element;
      var node = getClassReference(element);
      promoteToBodyLevel(node, element, declaration);
      classes.add(node);
    }

    void loadProcedure(FunctionDeclaration declaration) {
      var element = declaration.element;
      var node = getMemberReference(element);
      _buildTopLevelMember(node, element, declaration);
      procedures.add(node);
    }

    void loadField(TopLevelVariableDeclaration declaration) {
      for (var field in declaration.variables.variables) {
        var element = field.element;
        // Ignore fields inserted through error recovery.
        if (element.name == '') continue;
        var node = getMemberReference(element);
        _buildTopLevelMember(node, element, field);
        fields.add(node);
      }
    }

    for (var unit in units) {
      for (CompilationUnitMember declaration in unit.declarations) {
        if (declaration is ClassDeclaration ||
            declaration is EnumDeclaration ||
            declaration is ClassTypeAlias) {
          loadClass(declaration);
        } else if (declaration is FunctionDeclaration) {
          loadProcedure(declaration);
        } else if (declaration is TopLevelVariableDeclaration) {
          loadField(declaration);
        } else if (declaration is FunctionTypeAlias) {
          // Nothing to do. Typedefs are handled lazily while constructing type
          // references.
        } else {
          throw "unexpected node: ${declaration.runtimeType} $declaration";
        }
      }
    }
    libraryElements.add(element);
    _iterateTemporaryClassWorklist();
    // Ensure everything is stored in the original declaration order.
    library.classes
      ..clear()
      ..addAll(classes)
      ..addAll(_mixinApplications[library]?.values ?? const []);
    library.fields
      ..clear()
      ..addAll(fields);
    library.procedures
      ..clear()
      ..addAll(procedures);
    _libraryBeingLoaded = null;
  }

  LibraryElement getDartCoreLibrary() {
    return _dartCoreLibrary ??= _findLibraryElement('dart:core');
  }

  LibraryElement _findLibraryElement(String uri) {
    var source = context.sourceFactory.forUri(uri);
    if (source == null) return null;
    return context.computeLibraryElement(source);
  }

  ast.Class getRootClassReference() {
    return getCoreClassReference('Object');
  }

  ast.Constructor getRootClassConstructorReference() {
    var element = getDartCoreLibrary().getType('Object').constructors[0];
    return getMemberReference(element);
  }

  ast.Class getCoreClassReference(String className) {
    return getClassReference(getDartCoreLibrary().getType(className));
  }

  ast.Constructor getCoreClassConstructorReference(String className,
      {String constructorName, String library}) {
    LibraryElement libraryElement =
        library != null ? _findLibraryElement(library) : getDartCoreLibrary();
    ClassElement element = libraryElement.getType(className);
    if (element == null) {
      throw 'Missing core class $className from ${libraryElement.name}';
    }
    var constructor = element.constructors.firstWhere((constructor) {
      return (constructorName == null)
          ? (constructor.nameLength == 0)
          : (constructor.name == constructorName);
    });
    return getMemberReference(constructor);
  }

  ClassElement getClassElement(ast.Class node) {
    return _classes.inverse[node];
  }

  void addMixinClassToLibrary(ast.Class class_, ast.Library library) {
    assert(class_.parent == null);
    library.addClass(class_);
    var map =
        _mixinApplications.putIfAbsent(library, () => <String, ast.Class>{});
    map[class_.name] = class_;
  }

  /// Returns the IR for a class, at a temporary loading level.
  ///
  /// The returned class has the correct name, flags, type parameter arity,
  /// and enclosing library.
  ast.Class getClassReference(ClassElement element) {
    var classNode = _classes[element];
    if (classNode != null) return classNode;
    _classes[element] = classNode = new ast.Class(
        name: element.name,
        isAbstract: element.isAbstract,
        fileUri: '${element.source.uri}')
      ..fileOffset = element.nameOffset;
    classNode.level = ast.ClassLevel.Temporary;
    var library = getLibraryReference(element.library);
    library.addClass(classNode);
    // Initialize type parameter list without bounds.
    for (var parameter in element.typeParameters) {
      var parameterNode = new ast.TypeParameter(parameter.name);
      _classTypeParameters[parameter] = parameterNode;
      classNode.typeParameters.add(parameterNode);
      parameterNode.parent = classNode;
    }
    // Ensure the class is at least promoted to type level before exposing it
    // to kernel consumers.
    temporaryClassWorklist.add(classNode);
    return classNode;
  }

  /// Ensures the supertypes and type parameter bounds have been generated for
  /// the given class.
  void promoteToTypeLevel(ast.Class classNode) {
    if (classNode.level.index >= ast.ClassLevel.Type.index) return;
    classNode.level = ast.ClassLevel.Type;
    var element = getClassElement(classNode);
    assert(element != null);
    var library = getLibraryReference(element.library);
    var scope = new ClassScope(this, library);
    // Initialize bounds on type parameters.
    for (int i = 0; i < classNode.typeParameters.length; ++i) {
      var parameter = element.typeParameters[i];
      var parameterNode = classNode.typeParameters[i];
      parameterNode.bound = parameter.bound == null
          ? scope.defaultTypeParameterBound
          : scope.buildType(parameter.bound);
    }
    // Initialize supertypes.
    Iterable<InterfaceType> mixins = element.mixins;
    if (element.isMixinApplication && mixins.isNotEmpty) {
      classNode.mixedInType = scope.buildSupertype(mixins.last);
      mixins = mixins.take(mixins.length - 1);
    }
    if (element.supertype != null) {
      ast.Supertype supertype = scope.buildSupertype(element.supertype);
      bool useSharedMixin = true;
      for (var mixin in mixins) {
        var mixinType = scope.buildSupertype(mixin);
        if (useSharedMixin &&
            areDistinctUnboundTypeVariables(supertype, mixinType)) {
          // Use a shared mixin application class for this library.
          var mixinClass = getSharedMixinApplicationClass(
              scope.currentLibrary, supertype.classNode, mixinType.classNode);
          if (mixinClass.fileOffset < 0) {
            mixinClass.fileOffset = element.nameOffset;
          }
          supertype = new ast.Supertype(
              mixinClass,
              supertype.typeArguments.length > mixinType.typeArguments.length
                  ? supertype.typeArguments
                  : mixinType.typeArguments);
        } else {
          // Generate a new class specific for this mixin application.
          var freshParameters =
              getFreshTypeParameters(classNode.typeParameters);
          var mixinClass = new ast.Class(
              name: '${classNode.name}^${mixinType.classNode.name}',
              isAbstract: true,
              typeParameters: freshParameters.freshTypeParameters,
              supertype: freshParameters.substituteSuper(supertype),
              mixedInType: freshParameters.substituteSuper(mixinType),
              fileUri: classNode.fileUri)
            ..fileOffset = element.nameOffset;
          mixinClass.level = ast.ClassLevel.Type;
          addMixinClassToLibrary(mixinClass, classNode.enclosingLibrary);
          supertype = new ast.Supertype(mixinClass,
              classNode.typeParameters.map(makeTypeParameterType).toList());
          // This class cannot be used from anywhere else, so don't try to
          // generate shared mixin applications using it.
          useSharedMixin = false;
        }
      }
      classNode.supertype = supertype;
      for (var implementedType in element.interfaces) {
        classNode.implementedTypes.add(scope.buildSupertype(implementedType));
      }
    }
  }

  void promoteToHierarchyLevel(ast.Class classNode) {
    if (classNode.level.index >= ast.ClassLevel.Hierarchy.index) return;
    promoteToTypeLevel(classNode);
    classNode.level = ast.ClassLevel.Hierarchy;
    var element = getClassElement(classNode);
    if (element != null) {
      // Ensure all instance members are at present.
      for (var field in element.fields) {
        if (!field.isStatic && !field.isSynthetic) {
          getMemberReference(field);
        }
      }
      for (var accessor in element.accessors) {
        if (!accessor.isStatic && !accessor.isSynthetic) {
          getMemberReference(accessor);
        }
      }
      for (var method in element.methods) {
        if (!method.isStatic && !method.isSynthetic) {
          getMemberReference(method);
        }
      }
    }
    for (var supertype in classNode.supers) {
      promoteToHierarchyLevel(supertype.classNode);
    }
  }

  void promoteToMixinLevel(ast.Class classNode, ClassElement element,
      NamedCompilationUnitMember astNode) {
    if (classNode.level.index >= ast.ClassLevel.Mixin.index) return;
    _classBeingPromotedToMixin = element;
    promoteToHierarchyLevel(classNode);
    classNode.level = ast.ClassLevel.Mixin;
    // Clear out the member references that were put in the class.
    // The AST builder will load them all put back in the right order.
    classNode..fields.clear()..procedures.clear()..constructors.clear();
    new ClassBodyBuilder(this, classNode, element).build(astNode);
    _classBeingPromotedToMixin = null;

    // Ensure mixed-in classes are available.
    for (var mixin in element.mixins) {
      _ensureMixinBecomesLoaded(mixin.element);
    }
  }

  /// Ensures that [element] eventually becomes loaded at least at mixin level.
  void _ensureMixinBecomesLoaded(ClassElement element) {
    if (isClassBeingPromotedToMixin(element)) {
      return;
    }
    var class_ = getClassReference(element);
    if (class_.level.index >= ast.ClassLevel.Mixin.index) {
      return;
    }
    var list = mixinLibraryWorklist[element.library] ??= <ClassElement>[];
    list.add(element);
  }

  void promoteToBodyLevel(ast.Class classNode, ClassElement element,
      NamedCompilationUnitMember astNode) {
    if (classNode.level == ast.ClassLevel.Body) return;
    promoteToMixinLevel(classNode, element, astNode);
    classNode.level = ast.ClassLevel.Body;
    // This frontend delivers the same contents for classes at body and mixin
    // levels, even though as specified, the mixin level does not require all
    // the static members to be present.  So no additional work is needed.
  }

  ast.TypeParameter tryGetClassTypeParameter(TypeParameterElement element) {
    return _classTypeParameters[element];
  }

  Element getMemberElement(ast.Member node) {
    return _members.inverse[node];
  }

  ast.Member getMemberReference(Element element) {
    assert(element != null);
    assert(element is! Member); // Use the "base element".
    return _members[element] ??= _buildMemberReference(element);
  }

  ast.Member _buildMemberReference(Element element) {
    assert(element != null);
    var member = _buildOrphanedMemberReference(element);
    // Set the parent pointer and store it in the enclosing class or library.
    // If the enclosing library is being built from the AST, do not add the
    // member, since the AST builder will put it in there.
    var parent = element.enclosingElement;
    if (parent is ClassElement) {
      var class_ = getClassReference(parent);
      member.parent = class_;
      if (!isLibraryBeingLoaded(element.library)) {
        class_.addMember(member);
      }
    } else {
      var library = getLibraryReference(element.library);
      member.parent = library;
      if (!isLibraryBeingLoaded(element.library)) {
        library.addMember(member);
      }
    }
    return member;
  }

  ast.Member _buildOrphanedMemberReference(Element element) {
    assert(element != null);
    ClassElement classElement = element.enclosingElement is ClassElement
        ? element.enclosingElement
        : null;
    TypeScope scope = classElement != null
        ? new ClassScope(this, getLibraryReference(element.library))
        : new TypeScope(this);
    if (classElement != null) {
      getClassReference(classElement);
    }
    switch (element.kind) {
      case ElementKind.CONSTRUCTOR:
        ConstructorElement constructor = element;
        if (constructor.isFactory) {
          return new ast.Procedure(
              _nameOfMember(constructor),
              ast.ProcedureKind.Factory,
              scope.buildFunctionInterface(constructor),
              isAbstract: false,
              isStatic: true,
              isExternal: constructor.isExternal,
              isConst: constructor.isConst,
              fileUri: '${element.source.uri}')
            ..fileOffset = element.nameOffset;
        }
        return new ast.Constructor(scope.buildFunctionInterface(constructor),
            name: _nameOfMember(element),
            isConst: constructor.isConst,
            isExternal: constructor.isExternal,
            isSyntheticDefault: constructor.isSynthetic)
          ..fileOffset = element.nameOffset;

      case ElementKind.FIELD:
      case ElementKind.TOP_LEVEL_VARIABLE:
        VariableElement variable = element;
        return new ast.Field(_nameOfMember(variable),
            isStatic: variable.isStatic,
            isFinal: variable.isFinal,
            isConst: variable.isConst,
            type: scope.buildType(variable.type),
            fileUri: '${element.source.uri}')
          ..fileOffset = element.nameOffset;

      case ElementKind.METHOD:
      case ElementKind.GETTER:
      case ElementKind.SETTER:
      case ElementKind.FUNCTION:
        if (element is FunctionElement &&
            element.enclosingElement is! CompilationUnitElement) {
          throw 'Function $element is nested in ${element.enclosingElement} '
              'and hence is not a member';
        }
        ExecutableElement executable = element;
        return new ast.Procedure(
            _nameOfMember(element),
            _procedureKindOf(executable),
            scope.buildFunctionInterface(executable),
            isAbstract: executable.isAbstract,
            isStatic: executable.isStatic,
            isExternal: executable.isExternal,
            fileUri: '${element.source.uri}')
          ..fileOffset = element.nameOffset;

      default:
        throw 'Unexpected member kind: $element';
    }
  }

  ast.ProcedureKind _procedureKindOf(ExecutableElement element) {
    if (element is PropertyAccessorElement) {
      return element.isGetter
          ? ast.ProcedureKind.Getter
          : ast.ProcedureKind.Setter;
    }
    if (element is MethodElement) {
      if (element.isOperator) return ast.ProcedureKind.Operator;
      return ast.ProcedureKind.Method;
    }
    if (element is FunctionElement) {
      return ast.ProcedureKind.Method;
    }
    if (element is ConstructorElement) {
      assert(element.isFactory);
      return ast.ProcedureKind.Factory;
    }
    throw 'Unexpected procedure: $element';
  }

  ast.Name _nameOfMember(Element element) {
    // Use 'displayName' to avoid a trailing '=' for setters and 'name' to
    // ensure unary minus is called 'unary-'.
    String name =
        element is PropertyAccessorElement ? element.displayName : element.name;
    return new ast.Name(name, getLibraryReference(element.library));
  }

  /// True if the two types have form `C<T1 ... Tm>` and `D<T1 ... Tn>`, and
  /// `T1 ... TN` are distinct type variables with no upper bound, where
  /// `N = max(m,n)`.
  bool areDistinctUnboundTypeVariables(
      ast.Supertype first, ast.Supertype second) {
    var seen = new Set<ast.TypeParameter>();
    if (first.typeArguments.length < second.typeArguments.length) {
      var tmp = first;
      first = second;
      second = tmp;
    }
    for (int i = 0; i < first.typeArguments.length; ++i) {
      var firstArg = first.typeArguments[i];
      if (!(firstArg is ast.TypeParameterType &&
          seen.add(firstArg.parameter) &&
          firstArg.parameter.bound is ast.DynamicType)) {
        return false;
      }
      if (i < second.typeArguments.length &&
          firstArg != second.typeArguments[i]) {
        return false;
      }
    }
    return true;
  }

  /// Returns the canonical mixin application of two classes, instantiated with
  /// the same list of unbound type variables.
  ///
  /// Given two classes:
  ///     class C<C1 ... Cm>
  ///     class D<D1 ... Dn>
  ///
  /// This creates or reuses a mixin application class in the library of form:
  ///
  ///     abstract class C&D<T1 ... TN> = C<T1 ... Tm> with D<T1 ... Tn>
  ///
  /// where `N = max(m,n)`.
  ///
  /// Such a class can in general contain type errors due to incompatible
  /// inheritance from `C` and `D`.  This method therefore should only be called
  /// if a mixin application `C<S1 ... Sm> with D<S1 ... Sn>` is seen, where
  /// `S1 ... SN` are distinct, unbound type variables.
  ast.Class getSharedMixinApplicationClass(
      ast.Library library, ast.Class superclass, ast.Class mixedInClass) {
    // TODO(asgerf): Avoid potential name clash due to associativity.
    // As it is, these mixins get the same name:
    //   (A with B) with C
    //   A with (B with C)
    String name = '${superclass.name}&${mixedInClass.name}';
    return _mixinApplications
        .putIfAbsent(library, () => <String, ast.Class>{})
        .putIfAbsent(name, () {
      var fresh =
          superclass.typeParameters.length >= mixedInClass.typeParameters.length
              ? getFreshTypeParameters(superclass.typeParameters)
              : getFreshTypeParameters(mixedInClass.typeParameters);
      var typeArguments =
          fresh.freshTypeParameters.map(makeTypeParameterType).toList();
      var superArgs = typeArguments.length != superclass.typeParameters.length
          ? typeArguments.sublist(0, superclass.typeParameters.length)
          : typeArguments;
      var mixinArgs = typeArguments.length != mixedInClass.typeParameters.length
          ? typeArguments.sublist(0, mixedInClass.typeParameters.length)
          : typeArguments;
      var result = new ast.Class(
          name: name,
          isAbstract: true,
          typeParameters: fresh.freshTypeParameters,
          supertype: new ast.Supertype(superclass, superArgs),
          mixedInType: new ast.Supertype(mixedInClass, mixinArgs),
          fileUri: library.fileUri);
      result.level = ast.ClassLevel.Type;
      library.addClass(result);
      return result;
    });
  }

  String formatErrorMessage(
      AnalysisError error, String filename, LineInfo lines) {
    var location = lines.getLocation(error.offset);
    return '[error] ${error.message} ($filename, '
        'line ${location.lineNumber}, '
        'col ${location.columnNumber})';
  }

  void ensureLibraryIsLoaded(ast.Library node) {
    _ensureLibraryIsLoaded(node);
    _iterateMixinLibraryWorklist();
  }

  void _ensureLibraryIsLoaded(ast.Library node) {
    if (!node.isExternal) return;
    node.isExternal = false;
    var source = context.sourceFactory
        .forUri2(applicationRoot.absoluteUri(node.importUri));
    assert(source != null);
    var element = context.computeLibraryElement(source);
    var units = <CompilationUnit>[];
    bool reportErrors = node.importUri.scheme != 'dart';
    var tree = context.resolveCompilationUnit(source, element);
    units.add(tree);
    if (reportErrors) _processErrors(source);
    for (var part in element.parts) {
      var source = part.source;
      units.add(context.resolveCompilationUnit(source, element));
      if (reportErrors) _processErrors(source);
    }
    for (var import in element.imports) {
      if (import.isDeferred && import.prefix != null) {
        node.addDependency(new ast.LibraryDependency.deferredImport(
            getLibraryReference(import.importedLibrary), import.prefix.name));
      } else {
        node.addDependency(new ast.LibraryDependency.import(
            getLibraryReference(import.importedLibrary),
            name: import.prefix?.name));
      }
    }
    for (var export in element.exports) {
      node.addDependency(new ast.LibraryDependency.export(
          getLibraryReference(export.exportedLibrary)));
    }
    _buildLibraryBody(element, node, units);
  }

  void _processErrors(Source source) {
    LineInfo lines;
    for (var error in context.computeErrors(source)) {
      if (error.errorCode is CompileTimeErrorCode ||
          error.errorCode is ParserErrorCode ||
          error.errorCode is ScannerErrorCode ||
          error.errorCode is StrongModeCode) {
        lines ??= context.computeLineInfo(source);
        errors.add(formatErrorMessage(error, source.shortName, lines));
      }
    }
  }

  void loadSdkInterface(ast.Program program, Target target) {
    var requiredSdkMembers = target.requiredSdkClasses;
    for (var libraryUri in requiredSdkMembers.keys) {
      var source = context.sourceFactory.forUri2(Uri.parse(libraryUri));
      var libraryElement = context.computeLibraryElement(source);
      for (var member in requiredSdkMembers[libraryUri]) {
        var type = libraryElement.getType(member);
        if (type == null) {
          throw 'Could not find $member in $libraryUri';
        }
        promoteToTypeLevel(getClassReference(type));
      }
    }
    _iterateTemporaryClassWorklist();
    _iterateMixinLibraryWorklist();
  }

  void loadEverything({Target target, bool compileSdk}) {
    compileSdk ??= true;
    if (compileSdk) {
      ensureLibraryIsLoaded(getLibraryReference(getDartCoreLibrary()));
      if (target != null) {
        for (var uri in target.extraRequiredLibraries) {
          var library = _findLibraryElement(uri);
          if (library == null) {
            errors.add('Could not find required library $uri');
            continue;
          }
          ensureLibraryIsLoaded(getLibraryReference(library));
        }
      }
    }
    for (int i = 0; i < program.libraries.length; ++i) {
      var library = program.libraries[i];
      if (compileSdk || library.importUri.scheme != 'dart') {
        ensureLibraryIsLoaded(library);
      }
    }
  }

  /// Builds a list of sources that have been loaded.
  ///
  /// This operation may be expensive and should only be used for diagnostics.
  List<String> getLoadedFileNames() {
    var list = <String>[];
    for (var library in program.libraries) {
      LibraryElement element = context.computeLibraryElement(context
          .sourceFactory
          .forUri2(applicationRoot.absoluteUri(library.importUri)));
      for (var unit in element.units) {
        list.add(unit.source.fullName);
      }
    }
    return list;
  }

  void _iterateTemporaryClassWorklist() {
    while (temporaryClassWorklist.isNotEmpty) {
      var element = temporaryClassWorklist.removeLast();
      promoteToTypeLevel(element);
    }
  }

  void _iterateMixinLibraryWorklist() {
    // The worklist groups classes in the same library together so that we
    // request resolved ASTs for each library only once.
    while (mixinLibraryWorklist.isNotEmpty) {
      LibraryElement library = mixinLibraryWorklist.keys.first;
      _libraryBeingLoaded = library;
      List<ClassElement> classes = mixinLibraryWorklist.remove(library);
      for (var class_ in classes) {
        var classNode = getClassReference(class_);
        promoteToMixinLevel(classNode, class_, class_.computeNode());
      }
      _libraryBeingLoaded = null;
    }
    _iterateTemporaryClassWorklist();
  }

  ast.Procedure _getMainMethod(Uri uri) {
    Source source = context.sourceFactory.forUri2(uri);
    LibraryElement library = context.computeLibraryElement(source);
    var mainElement = library.entryPoint;
    if (mainElement == null) return null;
    var mainMember = getMemberReference(mainElement);
    if (mainMember is ast.Procedure && !mainMember.isAccessor) {
      return mainMember;
    }
    // Top-level 'main' getters are not supported at the moment.
    return null;
  }

  ast.Procedure _makeMissingMainMethod(ast.Library library) {
    var main = new ast.Procedure(
        new ast.Name('main'),
        ast.ProcedureKind.Method,
        new ast.FunctionNode(new ast.ExpressionStatement(new ast.Throw(
            new ast.StringLiteral('Program has no main method')))),
        isStatic: true)
      ..fileUri = library.fileUri;
    library.addMember(main);
    return main;
  }

  void loadProgram(Uri mainLibrary, {Target target, bool compileSdk}) {
    ast.Library library = getLibraryReferenceFromUri(mainLibrary);
    ensureLibraryIsLoaded(library);
    var mainMethod = _getMainMethod(mainLibrary);
    loadEverything(target: target, compileSdk: compileSdk);
    if (mainMethod == null) {
      mainMethod = _makeMissingMainMethod(library);
    }
    program.mainMethod = mainMethod;
    for (LibraryElement libraryElement in libraryElements) {
      for (CompilationUnitElement compilationUnitElement
          in libraryElement.units) {
        var source = compilationUnitElement.source;
        LineInfo lineInfo = context.computeLineInfo(source);
        List<int> sourceCode;
        try {
          sourceCode =
              const Utf8Encoder().convert(context.getContents(source).data);
        } catch (e) {
          // The source's contents could not be accessed.
          sourceCode = const <int>[];
        }
        program.uriToSource['${source.uri}'] =
            new ast.Source(lineInfo.lineStarts, sourceCode);
      }
    }
  }

  ast.Library loadLibrary(Uri uri) {
    ast.Library library = getLibraryReferenceFromUri(uri);
    ensureLibraryIsLoaded(library);
    return library;
  }
}

class Bimap<K, V> {
  final Map<K, V> nodeMap = <K, V>{};
  final Map<V, K> inverse = <V, K>{};

  bool containsKey(K key) => nodeMap.containsKey(key);

  V operator [](K key) => nodeMap[key];

  void operator []=(K key, V value) {
    assert(!nodeMap.containsKey(key));
    nodeMap[key] = value;
    inverse[value] = key;
  }
}

/// Creates [DartLoader]s for a given configuration, while reusing the
/// [DartSdk] and [Packages] object if possible.
class DartLoaderBatch {
  Packages packages;
  DartSdk dartSdk;

  String lastSdk;
  String lastPackagePath;
  bool lastStrongMode;

  Future<DartLoader> getLoader(ast.Program program, DartOptions options,
      {String packageDiscoveryPath}) async {
    if (dartSdk == null ||
        lastSdk != options.sdk ||
        lastStrongMode != options.strongMode) {
      lastSdk = options.sdk;
      lastStrongMode = options.strongMode;
      dartSdk = createDartSdk(options.sdk, strongMode: options.strongModeSdk);
    }
    if (packages == null ||
        lastPackagePath != options.packagePath ||
        packageDiscoveryPath != null) {
      lastPackagePath = options.packagePath;
      packages = await createPackages(options.packagePath,
          discoveryPath: packageDiscoveryPath);
    }
    return new DartLoader(program, options, packages, dartSdk: dartSdk);
  }
}

Future<Packages> createPackages(String packagePath,
    {String discoveryPath}) async {
  if (packagePath != null) {
    var absolutePath = new io.File(packagePath).absolute.path;
    if (await new io.Directory(packagePath).exists()) {
      return getPackagesDirectory(new Uri.file(absolutePath));
    } else if (await new io.File(packagePath).exists()) {
      return loadPackagesFile(new Uri.file(absolutePath));
    } else {
      throw 'Packages not found: $packagePath';
    }
  }
  if (discoveryPath != null) {
    return findPackagesFromFile(Uri.parse(discoveryPath));
  }
  return Packages.noPackages;
}

AnalysisOptions createAnalysisOptions(bool strongMode) {
  return new AnalysisOptionsImpl()
    ..strongMode = strongMode
    ..generateImplicitErrors = false
    ..generateSdkErrors = false
    ..preserveComments = false
    ..hint = false
    ..enableSuperMixins = true;
}

DartSdk createDartSdk(String path, {bool strongMode, bool isSummary}) {
  if (isSummary ?? false) {
    return new SummaryBasedDartSdk(path, strongMode);
  }
  var resources = PhysicalResourceProvider.INSTANCE;
  return new FolderBasedDartSdk(resources, resources.getFolder(path))
    ..context
        .analysisOptions
        .setCrossContextOptionsFrom(createAnalysisOptions(strongMode));
}

class CustomUriResolver extends UriResolver {
  final ResourceUriResolver _resourceUriResolver;
  final Map<Uri, Uri> _customUrlMappings;

  CustomUriResolver(this._resourceUriResolver, this._customUrlMappings);

  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
    // TODO(kustermann): Once dartk supports configurable imports we should be
    // able to get rid of this.
    if (uri.toString() == 'package:mojo/src/internal_contract.dart') {
      uri = actualUri = Uri.parse('dart:mojo.internal');
    }

    Uri baseUri = uri;
    String relative;
    String path = uri.path;
    int index = path.indexOf('/');
    if (index > 0) {
      baseUri = uri.replace(path: path.substring(0, index));
      relative = path.substring(index + 1);
    }
    Uri baseMapped = _customUrlMappings[baseUri];
    if (baseMapped == null) return null;

    Uri mapped = relative != null ? baseMapped.resolve(relative) : baseMapped;
    return _resourceUriResolver.resolveAbsolute(mapped, actualUri);
  }

  Uri restoreAbsolute(Source source) {
    return _resourceUriResolver.restoreAbsolute(source);
  }
}

AnalysisContext createContext(DartOptions options, Packages packages,
    {DartSdk dartSdk}) {
  bool fromSummary = options.sdkSummary != null;
  dartSdk ??= createDartSdk(fromSummary ? options.sdkSummary : options.sdk,
      strongMode: options.strongModeSdk, isSummary: fromSummary);

  var resourceProvider = PhysicalResourceProvider.INSTANCE;
  var resourceUriResolver = new ResourceUriResolver(resourceProvider);
  List<UriResolver> resolvers = [];
  var customUriMappings = options.customUriMappings;
  if (customUriMappings != null && customUriMappings.length > 0) {
    resolvers
        .add(new CustomUriResolver(resourceUriResolver, customUriMappings));
  }
  resolvers.add(new DartUriResolver(dartSdk));
  resolvers.add(resourceUriResolver);

  if (packages != null) {
    var folderMap = <String, List<Folder>>{};
    packages.asMap().forEach((String packagePath, Uri uri) {
      String path = resourceProvider.pathContext.fromUri(uri);
      folderMap[packagePath] = [resourceProvider.getFolder(path)];
    });
    resolvers.add(new PackageMapUriResolver(resourceProvider, folderMap));
  }

  AnalysisContext context = AnalysisEngine.instance.createAnalysisContext()
    ..sourceFactory = new SourceFactory(resolvers)
    ..analysisOptions = createAnalysisOptions(options.strongMode);

  options.declaredVariables.forEach((String name, String value) {
    context.declaredVariables.define(name, value);
  });

  return context;
}
