| Index: pkg/kernel/lib/analyzer/loader.dart
|
| diff --git a/pkg/kernel/lib/analyzer/loader.dart b/pkg/kernel/lib/analyzer/loader.dart
|
| deleted file mode 100644
|
| index ca502282a71732f7dec6a94bffe4f6a0735e5880..0000000000000000000000000000000000000000
|
| --- a/pkg/kernel/lib/analyzer/loader.dart
|
| +++ /dev/null
|
| @@ -1,1004 +0,0 @@
|
| -// 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/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/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 '../ast.dart' as ast;
|
| -import '../target/targets.dart' show Target;
|
| -import '../type_algebra.dart';
|
| -import 'analyzer.dart';
|
| -import '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)
|
| - ..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);
|
| - }
|
| - _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;
|
| -}
|
|
|