| // Copyright (c) 2015, 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 analyzer.src.task.dart; |
| |
| import 'dart:collection'; |
| import 'dart:math' as math; |
| |
| import 'package:analyzer/src/generated/ast.dart'; |
| import 'package:analyzer/src/generated/element.dart'; |
| import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; |
| import 'package:analyzer/src/generated/error.dart'; |
| import 'package:analyzer/src/generated/error_verifier.dart'; |
| import 'package:analyzer/src/generated/java_engine.dart'; |
| import 'package:analyzer/src/generated/parser.dart'; |
| import 'package:analyzer/src/generated/resolver.dart'; |
| import 'package:analyzer/src/generated/scanner.dart'; |
| import 'package:analyzer/src/generated/sdk.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/generated/utilities_general.dart'; |
| import 'package:analyzer/src/task/driver.dart'; |
| import 'package:analyzer/src/task/general.dart'; |
| import 'package:analyzer/task/dart.dart'; |
| import 'package:analyzer/task/general.dart'; |
| import 'package:analyzer/task/model.dart'; |
| |
| /** |
| * The errors produced while resolving a library directives. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<List<AnalysisError>> BUILD_DIRECTIVES_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'BUILD_DIRECTIVES_ERRORS', AnalysisError.NO_ERRORS, |
| contributesTo: DART_ERRORS); |
| |
| /** |
| * The errors produced while building function type aliases. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<List<AnalysisError>> BUILD_FUNCTION_TYPE_ALIASES_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'BUILD_FUNCTION_TYPE_ALIASES_ERRORS', AnalysisError.NO_ERRORS, |
| contributesTo: DART_ERRORS); |
| |
| /** |
| * The errors produced while building a library element. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<List<AnalysisError>> BUILD_LIBRARY_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'BUILD_LIBRARY_ERRORS', AnalysisError.NO_ERRORS, |
| contributesTo: DART_ERRORS); |
| |
| /** |
| * The [ClassElement]s of a [LibraryUnitTarget]. |
| */ |
| final ListResultDescriptor<ClassElement> CLASS_ELEMENTS = |
| new ListResultDescriptor<ClassElement>('CLASS_ELEMENTS', null); |
| |
| /** |
| * The element model associated with a single compilation unit. |
| * |
| * The result is only available for targets representing a Dart compilation unit. |
| */ |
| final ResultDescriptor<CompilationUnitElement> COMPILATION_UNIT_ELEMENT = |
| new ResultDescriptor<CompilationUnitElement>( |
| 'COMPILATION_UNIT_ELEMENT', null); |
| |
| /** |
| * The [ConstructorElement]s of a [ClassElement]. |
| */ |
| final ResultDescriptor<List<ConstructorElement>> CONSTRUCTORS = |
| new ResultDescriptor<List<ConstructorElement>>('CONSTRUCTORS', null); |
| |
| /** |
| * The errors produced while building a [ClassElement] constructors. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a [ClassElement]. |
| */ |
| final ResultDescriptor<List<AnalysisError>> CONSTRUCTORS_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'CONSTRUCTORS_ERRORS', AnalysisError.NO_ERRORS); |
| |
| /** |
| * The sources representing the export closure of a library. |
| * The [Source]s include only library sources, not their units. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ListResultDescriptor<Source> EXPORT_SOURCE_CLOSURE = |
| new ListResultDescriptor<Source>('EXPORT_SOURCE_CLOSURE', null); |
| |
| /** |
| * The errors produced while generating hints a compilation unit. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart compilation unit. |
| */ |
| final ResultDescriptor<List<AnalysisError>> HINTS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'HINT_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS); |
| |
| /** |
| * The sources representing the import closure of a library. |
| * The [Source]s include only library sources, not their units. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ListResultDescriptor<Source> IMPORT_SOURCE_CLOSURE = |
| new ListResultDescriptor<Source>('IMPORT_SOURCE_CLOSURE', null); |
| |
| /** |
| * The partial [LibraryElement] associated with a library. |
| * |
| * The [LibraryElement] and its [CompilationUnitElement]s are attached to each |
| * other. Directives 'library', 'part' and 'part of' are resolved. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT1 = |
| new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT1', null); |
| |
| /** |
| * The partial [LibraryElement] associated with a library. |
| * |
| * In addition to [LIBRARY_ELEMENT1] [LibraryElement.imports] and |
| * [LibraryElement.exports] are set. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT2 = |
| new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT2', null); |
| |
| /** |
| * The partial [LibraryElement] associated with a library. |
| * |
| * In addition to [LIBRARY_ELEMENT2] the [LibraryElement.publicNamespace] is set. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT3 = |
| new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT3', null); |
| |
| /** |
| * The partial [LibraryElement] associated with a library. |
| * |
| * In addition to [LIBRARY_ELEMENT3] the [LibraryElement.entryPoint] is set, |
| * if the library does not declare one already and one of the exported |
| * libraries exports one. |
| * |
| * Also [LibraryElement.exportNamespace] is set. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT4 = |
| new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT4', null); |
| |
| /** |
| * The partial [LibraryElement] associated with a library. |
| * |
| * [LIBRARY_ELEMENT4] plus [RESOLVED_UNIT4] for every unit. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT5 = |
| new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null); |
| |
| /** |
| * The errors produced while parsing a compilation unit. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart compilation unit. |
| */ |
| final ResultDescriptor<List<AnalysisError>> PARSE_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'PARSE_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS); |
| |
| /** |
| * The errors produced while resolving references. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a unit. |
| */ |
| final ResultDescriptor<List<AnalysisError>> RESOLVE_REFERENCES_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'RESOLVE_REFERENCES_ERRORS', AnalysisError.NO_ERRORS, |
| contributesTo: DART_ERRORS); |
| |
| /** |
| * The errors produced while resolving type names. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart library. |
| */ |
| final ResultDescriptor<List<AnalysisError>> RESOLVE_TYPE_NAMES_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'RESOLVE_TYPE_NAMES_ERRORS', AnalysisError.NO_ERRORS, |
| contributesTo: DART_ERRORS); |
| |
| /** |
| * The partially resolved [CompilationUnit] associated with a unit. |
| * |
| * All declarations bound to the element defined by the declaration. |
| * |
| * The result is only available for targets representing a unit. |
| */ |
| final ResultDescriptor<CompilationUnit> RESOLVED_UNIT1 = |
| new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT1', null); |
| |
| /** |
| * The partially resolved [CompilationUnit] associated with a unit. |
| * |
| * All the enum member elements are built. |
| * |
| * The result is only available for targets representing a unit. |
| */ |
| final ResultDescriptor<CompilationUnit> RESOLVED_UNIT2 = |
| new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT2', null); |
| |
| /** |
| * The partially resolved [CompilationUnit] associated with a unit. |
| * |
| * All the function type aliases are resolved. |
| * |
| * The result is only available for targets representing a unit. |
| */ |
| final ResultDescriptor<CompilationUnit> RESOLVED_UNIT3 = |
| new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT3', null); |
| |
| /** |
| * The partially resolved [CompilationUnit] associated with a unit. |
| * |
| * [RESOLVED_UNIT3] with resolved type names. |
| * |
| * The result is only available for targets representing a unit. |
| */ |
| final ResultDescriptor<CompilationUnit> RESOLVED_UNIT4 = |
| new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT4', null); |
| |
| /** |
| * The partially resolved [CompilationUnit] associated with a unit. |
| * |
| * [RESOLVED_UNIT4] plus resolved local variables and formal parameters. |
| * |
| * The result is only available for targets representing a unit. |
| */ |
| final ResultDescriptor<CompilationUnit> RESOLVED_UNIT5 = |
| new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT5', null); |
| |
| /** |
| * The errors produced while scanning a compilation unit. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart compilation unit. |
| */ |
| final ResultDescriptor<List<AnalysisError>> SCAN_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'SCAN_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS); |
| |
| /** |
| * The [TypeProvider] of the context. |
| */ |
| final ResultDescriptor<TypeProvider> TYPE_PROVIDER = |
| new ResultDescriptor<TypeProvider>('TYPE_PROVIDER', null); |
| |
| /** |
| * The [UsedImportedElements] of a [LibraryUnitTarget]. |
| */ |
| final ResultDescriptor<UsedImportedElements> USED_IMPORTED_ELEMENTS = |
| new ResultDescriptor<UsedImportedElements>('USED_IMPORTED_ELEMENTS', null); |
| |
| /** |
| * The [UsedLocalElements] of a [LibraryUnitTarget]. |
| */ |
| final ResultDescriptor<UsedLocalElements> USED_LOCAL_ELEMENTS = |
| new ResultDescriptor<UsedLocalElements>('USED_LOCAL_ELEMENTS', null); |
| |
| /** |
| * The errors produced while verifying a compilation unit. |
| * |
| * The list will be empty if there were no errors, but will not be `null`. |
| * |
| * The result is only available for targets representing a Dart compilation unit. |
| */ |
| final ResultDescriptor<List<AnalysisError>> VERIFY_ERRORS = |
| new ResultDescriptor<List<AnalysisError>>( |
| 'VERIFY_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS); |
| |
| /** |
| * A task that builds implicit constructors for a [ClassElement], or keeps |
| * the existing explicit constructors if the class has them. |
| */ |
| class BuildClassConstructorsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [CONSTRUCTORS] input for the superclass. |
| */ |
| static const String SUPER_CONSTRUCTORS = 'SUPER_CONSTRUCTORS'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildConstructorsForClassTask', createTask, buildInputs, |
| <ResultDescriptor>[CONSTRUCTORS, CONSTRUCTORS_ERRORS]); |
| |
| BuildClassConstructorsTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| List<AnalysisError> errors = <AnalysisError>[]; |
| // |
| // Prepare inputs. |
| // |
| ClassElementImpl classElement = this.target; |
| List<ConstructorElement> superConstructors = inputs[SUPER_CONSTRUCTORS]; |
| DartType superType = classElement.supertype; |
| ClassElement superElement = superType.element; |
| // |
| // Shortcut for ClassElement(s) without implicit constructors. |
| // |
| if (superConstructors == null) { |
| outputs[CONSTRUCTORS] = classElement.constructors; |
| outputs[CONSTRUCTORS_ERRORS] = AnalysisError.NO_ERRORS; |
| return; |
| } |
| // |
| // ClassTypeAlias |
| // |
| if (classElement.isTypedef) { |
| List<ConstructorElement> implicitConstructors = |
| new List<ConstructorElement>(); |
| void callback(ConstructorElement explicitConstructor, |
| List<DartType> parameterTypes, List<DartType> argumentTypes) { |
| implicitConstructors.add(_createImplicitContructor(classElement.type, |
| explicitConstructor, parameterTypes, argumentTypes)); |
| } |
| if (_findForwardedConstructors(classElement, superType, callback)) { |
| if (implicitConstructors.isEmpty) { |
| errors.add(new AnalysisError.con2(classElement.source, |
| classElement.nameOffset, classElement.name.length, |
| CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS, |
| [superElement.name])); |
| } else { |
| classElement.constructors = implicitConstructors; |
| } |
| } |
| outputs[CONSTRUCTORS] = classElement.constructors; |
| outputs[CONSTRUCTORS_ERRORS] = errors; |
| } |
| // |
| // ClassDeclaration |
| // |
| if (!classElement.isTypedef) { |
| bool constructorFound = false; |
| void callback(ConstructorElement explicitConstructor, |
| List<DartType> parameterTypes, List<DartType> argumentTypes) { |
| constructorFound = true; |
| } |
| if (_findForwardedConstructors(classElement, superType, callback) && |
| !constructorFound) { |
| SourceRange withRange = classElement.withClauseRange; |
| errors.add(new AnalysisError.con2(classElement.source, withRange.offset, |
| withRange.length, CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS, |
| [superElement.name])); |
| classElement.mixinErrorsReported = true; |
| } |
| outputs[CONSTRUCTORS] = classElement.constructors; |
| outputs[CONSTRUCTORS_ERRORS] = errors; |
| } |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [classElement]. |
| */ |
| static Map<String, TaskInput> buildInputs(ClassElement classElement) { |
| // TODO(scheglov) Here we implicitly depend on LIBRARY_ELEMENT5, i.e. that |
| // "supertype" for the "classElement" is set. |
| // We need to make it an explicit dependency. |
| DartType superType = classElement.supertype; |
| if (superType is InterfaceType) { |
| if (classElement.isTypedef || classElement.mixins.isNotEmpty) { |
| ClassElement superElement = superType.element; |
| return <String, TaskInput>{ |
| SUPER_CONSTRUCTORS: CONSTRUCTORS.of(superElement) |
| }; |
| } |
| } |
| // No implicit constructors, no inputs required. |
| return <String, TaskInput>{}; |
| } |
| |
| /** |
| * Create a [BuildClassConstructorsTask] based on the given |
| * [target] in the given [context]. |
| */ |
| static BuildClassConstructorsTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildClassConstructorsTask(context, target); |
| } |
| |
| /** |
| * Create an implicit constructor that is copied from the given |
| * [explicitConstructor], but that is in the given class. |
| * |
| * [classType] - the class in which the implicit constructor is defined. |
| * [explicitConstructor] - the constructor on which the implicit constructor |
| * is modeled. |
| * [parameterTypes] - the types to be replaced when creating parameters. |
| * [argumentTypes] - the types with which the parameters are to be replaced. |
| */ |
| static ConstructorElement _createImplicitContructor(InterfaceType classType, |
| ConstructorElement explicitConstructor, List<DartType> parameterTypes, |
| List<DartType> argumentTypes) { |
| ConstructorElementImpl implicitConstructor = |
| new ConstructorElementImpl(explicitConstructor.name, -1); |
| implicitConstructor.synthetic = true; |
| implicitConstructor.redirectedConstructor = explicitConstructor; |
| implicitConstructor.const2 = explicitConstructor.isConst; |
| implicitConstructor.returnType = classType; |
| List<ParameterElement> explicitParameters = explicitConstructor.parameters; |
| int count = explicitParameters.length; |
| if (count > 0) { |
| List<ParameterElement> implicitParameters = |
| new List<ParameterElement>(count); |
| for (int i = 0; i < count; i++) { |
| ParameterElement explicitParameter = explicitParameters[i]; |
| ParameterElementImpl implicitParameter = |
| new ParameterElementImpl(explicitParameter.name, -1); |
| implicitParameter.const3 = explicitParameter.isConst; |
| implicitParameter.final2 = explicitParameter.isFinal; |
| implicitParameter.parameterKind = explicitParameter.parameterKind; |
| implicitParameter.synthetic = true; |
| implicitParameter.type = |
| explicitParameter.type.substitute2(argumentTypes, parameterTypes); |
| implicitParameters[i] = implicitParameter; |
| } |
| implicitConstructor.parameters = implicitParameters; |
| } |
| FunctionTypeImpl type = new FunctionTypeImpl.con1(implicitConstructor); |
| type.typeArguments = classType.typeArguments; |
| implicitConstructor.type = type; |
| return implicitConstructor; |
| } |
| |
| /** |
| * Find all the constructors that should be forwarded from the given |
| * [superType], to the class or mixin application [classElement], |
| * and pass information about them to [callback]. |
| * |
| * Return true if some constructors were considered. (A false return value |
| * can only happen if the supeclass is a built-in type, in which case it |
| * can't be used as a mixin anyway). |
| */ |
| static bool _findForwardedConstructors(ClassElementImpl classElement, |
| InterfaceType superType, void callback( |
| ConstructorElement explicitConstructor, List<DartType> parameterTypes, |
| List<DartType> argumentTypes)) { |
| ClassElement superclassElement = superType.element; |
| List<ConstructorElement> constructors = superclassElement.constructors; |
| int count = constructors.length; |
| if (count == 0) { |
| return false; |
| } |
| List<DartType> parameterTypes = |
| TypeParameterTypeImpl.getTypes(superType.typeParameters); |
| List<DartType> argumentTypes = _getArgumentTypes(superType, parameterTypes); |
| for (int i = 0; i < count; i++) { |
| ConstructorElement explicitConstructor = constructors[i]; |
| if (!explicitConstructor.isFactory && |
| classElement.isSuperConstructorAccessible(explicitConstructor)) { |
| callback(explicitConstructor, parameterTypes, argumentTypes); |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Return a list of argument types that corresponds to the [parameterTypes] |
| * and that are derived from the type arguments of the given [superType]. |
| */ |
| static List<DartType> _getArgumentTypes( |
| InterfaceType superType, List<DartType> parameterTypes) { |
| DynamicTypeImpl dynamic = DynamicTypeImpl.instance; |
| int parameterCount = parameterTypes.length; |
| List<DartType> types = new List<DartType>(parameterCount); |
| if (superType == null) { |
| types = new List<DartType>.filled(parameterCount, dynamic); |
| } else { |
| List<DartType> typeArguments = superType.typeArguments; |
| int argumentCount = math.min(typeArguments.length, parameterCount); |
| for (int i = 0; i < argumentCount; i++) { |
| types[i] = typeArguments[i]; |
| } |
| for (int i = argumentCount; i < parameterCount; i++) { |
| types[i] = dynamic; |
| } |
| } |
| return types; |
| } |
| } |
| |
| /** |
| * A task that builds a compilation unit element for a single compilation unit. |
| */ |
| class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input whose value is the line information for the |
| * compilation unit. |
| */ |
| static const String LINE_INFO_INPUT_NAME = 'LINE_INFO_INPUT_NAME'; |
| |
| /** |
| * The name of the input whose value is the AST for the compilation unit. |
| */ |
| static const String PARSED_UNIT_INPUT_NAME = 'PARSED_UNIT_INPUT_NAME'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildCompilationUnitElementTask', createTask, buildInputs, |
| <ResultDescriptor>[ |
| CLASS_ELEMENTS, |
| COMPILATION_UNIT_ELEMENT, |
| RESOLVED_UNIT1 |
| ]); |
| |
| /** |
| * Initialize a newly created task to build a compilation unit element for |
| * the given [target] in the given [context]. |
| */ |
| BuildCompilationUnitElementTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| // |
| // Prepare inputs. |
| // |
| Source source = getRequiredSource(); |
| CompilationUnit unit = getRequiredInput(PARSED_UNIT_INPUT_NAME); |
| // |
| // Process inputs. |
| // |
| unit = AstCloner.clone(unit); |
| CompilationUnitBuilder builder = new CompilationUnitBuilder(); |
| CompilationUnitElement element = builder.buildCompilationUnit(source, unit); |
| // |
| // Record outputs. |
| // |
| outputs[CLASS_ELEMENTS] = element.types; |
| outputs[COMPILATION_UNIT_ELEMENT] = element; |
| outputs[RESOLVED_UNIT1] = unit; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the given |
| * [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{ |
| PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(target.unit) |
| }; |
| } |
| |
| /** |
| * Create a [BuildCompilationUnitElementTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildCompilationUnitElementTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildCompilationUnitElementTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds imports and export directive elements for a library. |
| */ |
| class BuildDirectiveElementsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input for [RESOLVED_UNIT1] of a library unit. |
| */ |
| static const String UNIT_INPUT_NAME = 'UNIT_INPUT_NAME'; |
| |
| /** |
| * The input with a list of [LIBRARY_ELEMENT3]s of imported libraries. |
| */ |
| static const String IMPORTS_LIBRARY_ELEMENT_INPUT_NAME = |
| 'IMPORTS_LIBRARY_ELEMENT1_INPUT_NAME'; |
| |
| /** |
| * The input with a list of [LIBRARY_ELEMENT3]s of exported libraries. |
| */ |
| static const String EXPORTS_LIBRARY_ELEMENT_INPUT_NAME = |
| 'EXPORTS_LIBRARY_ELEMENT_INPUT_NAME'; |
| |
| /** |
| * The input with a list of [SOURCE_KIND]s of imported libraries. |
| */ |
| static const String IMPORTS_SOURCE_KIND_INPUT_NAME = |
| 'IMPORTS_SOURCE_KIND_INPUT_NAME'; |
| |
| /** |
| * The input with a list of [SOURCE_KIND]s of exported libraries. |
| */ |
| static const String EXPORTS_SOURCE_KIND_INPUT_NAME = |
| 'EXPORTS_SOURCE_KIND_INPUT_NAME'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildDirectiveElementsTask', createTask, buildInputs, <ResultDescriptor>[ |
| LIBRARY_ELEMENT2, |
| BUILD_DIRECTIVES_ERRORS |
| ]); |
| |
| BuildDirectiveElementsTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| List<AnalysisError> errors = <AnalysisError>[]; |
| // |
| // Prepare inputs. |
| // |
| CompilationUnit libraryUnit = getRequiredInput(UNIT_INPUT_NAME); |
| Map<Source, LibraryElement> importLibraryMap = |
| getRequiredInput(IMPORTS_LIBRARY_ELEMENT_INPUT_NAME); |
| Map<Source, LibraryElement> exportLibraryMap = |
| getRequiredInput(EXPORTS_LIBRARY_ELEMENT_INPUT_NAME); |
| Map<Source, SourceKind> importSourceKindMap = |
| getRequiredInput(IMPORTS_SOURCE_KIND_INPUT_NAME); |
| Map<Source, SourceKind> exportSourceKindMap = |
| getRequiredInput(EXPORTS_SOURCE_KIND_INPUT_NAME); |
| // |
| // Process inputs. |
| // |
| LibraryElementImpl libraryElement = libraryUnit.element.library; |
| Source librarySource = libraryElement.source; |
| // |
| // Resolve directives. |
| // |
| HashMap<String, PrefixElementImpl> nameToPrefixMap = |
| new HashMap<String, PrefixElementImpl>(); |
| List<ImportElement> imports = <ImportElement>[]; |
| List<ExportElement> exports = <ExportElement>[]; |
| bool explicitlyImportsCore = false; |
| for (Directive directive in libraryUnit.directives) { |
| if (directive is ImportDirective) { |
| ImportDirective importDirective = directive; |
| String uriContent = importDirective.uriContent; |
| if (DartUriResolver.isDartExtUri(uriContent)) { |
| libraryElement.hasExtUri = true; |
| } |
| Source importedSource = importDirective.source; |
| if (importedSource != null && context.exists(importedSource)) { |
| // The imported source will be null if the URI in the import |
| // directive was invalid. |
| LibraryElement importedLibrary = importLibraryMap[importedSource]; |
| if (importedLibrary != null) { |
| ImportElementImpl importElement = |
| new ImportElementImpl(directive.offset); |
| StringLiteral uriLiteral = importDirective.uri; |
| if (uriLiteral != null) { |
| importElement.uriOffset = uriLiteral.offset; |
| importElement.uriEnd = uriLiteral.end; |
| } |
| importElement.uri = uriContent; |
| importElement.deferred = importDirective.deferredKeyword != null; |
| importElement.combinators = _buildCombinators(importDirective); |
| importElement.importedLibrary = importedLibrary; |
| SimpleIdentifier prefixNode = directive.prefix; |
| if (prefixNode != null) { |
| importElement.prefixOffset = prefixNode.offset; |
| String prefixName = prefixNode.name; |
| PrefixElementImpl prefix = nameToPrefixMap[prefixName]; |
| if (prefix == null) { |
| prefix = new PrefixElementImpl.forNode(prefixNode); |
| nameToPrefixMap[prefixName] = prefix; |
| } |
| importElement.prefix = prefix; |
| prefixNode.staticElement = prefix; |
| } |
| directive.element = importElement; |
| imports.add(importElement); |
| if (importSourceKindMap[importedSource] != SourceKind.LIBRARY) { |
| ErrorCode errorCode = (importElement.isDeferred |
| ? StaticWarningCode.IMPORT_OF_NON_LIBRARY |
| : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY); |
| errors.add(new AnalysisError.con2(importedSource, |
| uriLiteral.offset, uriLiteral.length, errorCode, |
| [uriLiteral.toSource()])); |
| } |
| } |
| } |
| } else if (directive is ExportDirective) { |
| ExportDirective exportDirective = directive; |
| Source exportedSource = exportDirective.source; |
| if (exportedSource != null && context.exists(exportedSource)) { |
| // The exported source will be null if the URI in the export |
| // directive was invalid. |
| LibraryElement exportedLibrary = exportLibraryMap[exportedSource]; |
| if (exportedLibrary != null) { |
| ExportElementImpl exportElement = |
| new ExportElementImpl(directive.offset); |
| StringLiteral uriLiteral = exportDirective.uri; |
| if (uriLiteral != null) { |
| exportElement.uriOffset = uriLiteral.offset; |
| exportElement.uriEnd = uriLiteral.end; |
| } |
| exportElement.uri = exportDirective.uriContent; |
| exportElement.combinators = _buildCombinators(exportDirective); |
| exportElement.exportedLibrary = exportedLibrary; |
| directive.element = exportElement; |
| exports.add(exportElement); |
| if (exportSourceKindMap[exportedSource] != SourceKind.LIBRARY) { |
| errors.add(new AnalysisError.con2(exportedSource, |
| uriLiteral.offset, uriLiteral.length, |
| CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, |
| [uriLiteral.toSource()])); |
| } |
| } |
| } |
| } |
| } |
| // |
| // Ensure "dart:core" import. |
| // |
| Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE); |
| if (!explicitlyImportsCore && coreLibrarySource != librarySource) { |
| ImportElementImpl importElement = new ImportElementImpl(-1); |
| importElement.importedLibrary = importLibraryMap[coreLibrarySource]; |
| importElement.synthetic = true; |
| imports.add(importElement); |
| } |
| // |
| // Populate the library element. |
| // |
| libraryElement.imports = imports; |
| libraryElement.exports = exports; |
| // |
| // Record outputs. |
| // |
| outputs[LIBRARY_ELEMENT2] = libraryElement; |
| outputs[BUILD_DIRECTIVES_ERRORS] = errors; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given library [libSource]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{ |
| 'defining_LIBRARY_ELEMENT1': LIBRARY_ELEMENT1.of(libSource), |
| UNIT_INPUT_NAME: |
| RESOLVED_UNIT1.of(new LibraryUnitTarget(libSource, libSource)), |
| IMPORTS_LIBRARY_ELEMENT_INPUT_NAME: |
| IMPORTED_LIBRARIES.of(libSource).toMapOf(LIBRARY_ELEMENT1), |
| EXPORTS_LIBRARY_ELEMENT_INPUT_NAME: |
| EXPORTED_LIBRARIES.of(libSource).toMapOf(LIBRARY_ELEMENT1), |
| IMPORTS_SOURCE_KIND_INPUT_NAME: |
| IMPORTED_LIBRARIES.of(libSource).toMapOf(SOURCE_KIND), |
| EXPORTS_SOURCE_KIND_INPUT_NAME: |
| EXPORTED_LIBRARIES.of(libSource).toMapOf(SOURCE_KIND) |
| }; |
| } |
| |
| /** |
| * Create a [BuildDirectiveElementsTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildDirectiveElementsTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildDirectiveElementsTask(context, target); |
| } |
| |
| /** |
| * Build the element model representing the combinators declared by |
| * the given [directive]. |
| */ |
| static List<NamespaceCombinator> _buildCombinators( |
| NamespaceDirective directive) { |
| List<NamespaceCombinator> combinators = <NamespaceCombinator>[]; |
| for (Combinator combinator in directive.combinators) { |
| if (combinator is ShowCombinator) { |
| ShowElementCombinatorImpl show = new ShowElementCombinatorImpl(); |
| show.offset = combinator.offset; |
| show.end = combinator.end; |
| show.shownNames = _getIdentifiers(combinator.shownNames); |
| combinators.add(show); |
| } else if (combinator is HideCombinator) { |
| HideElementCombinatorImpl hide = new HideElementCombinatorImpl(); |
| hide.hiddenNames = _getIdentifiers(combinator.hiddenNames); |
| combinators.add(hide); |
| } |
| } |
| return combinators; |
| } |
| |
| /** |
| * Return the lexical identifiers associated with the given [identifiers]. |
| */ |
| static List<String> _getIdentifiers(NodeList<SimpleIdentifier> identifiers) { |
| return identifiers.map((identifier) => identifier.name).toList(); |
| } |
| } |
| |
| /** |
| * A task that builds the elements representing the members of enum |
| * declarations. |
| */ |
| class BuildEnumMemberElementsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [TYPE_PROVIDER] input. |
| */ |
| static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| |
| /** |
| * The name of the [RESOLVED_UNIT1] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildEnumMemberElementsTask', createTask, buildInputs, |
| <ResultDescriptor>[RESOLVED_UNIT2]); |
| |
| BuildEnumMemberElementsTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| // |
| // Prepare inputs. |
| // |
| TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| // |
| // Record outputs. |
| // |
| EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider); |
| unit.accept(builder); |
| outputs[RESOLVED_UNIT2] = unit; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{ |
| TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request), |
| UNIT_INPUT: RESOLVED_UNIT1.of(target) |
| }; |
| } |
| |
| /** |
| * Create a [BuildEnumMemberElementsTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildEnumMemberElementsTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildEnumMemberElementsTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [EXPORT_NAMESPACE] and [LIBRARY_ELEMENT4] for a library. |
| */ |
| class BuildExportNamespaceTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input for [LIBRARY_ELEMENT3] of a library. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildExportNamespaceTask', createTask, buildInputs, |
| <ResultDescriptor>[LIBRARY_ELEMENT4]); |
| |
| BuildExportNamespaceTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| LibraryElementImpl library = getRequiredInput(LIBRARY_INPUT); |
| // |
| // Compute export namespace. |
| // |
| ExportNamespaceBuilder builder = new ExportNamespaceBuilder(); |
| Namespace namespace = builder.build(library); |
| library.exportNamespace = namespace; |
| // |
| // Update entry point. |
| // |
| if (library.entryPoint == null) { |
| Iterable<Element> exportedElements = namespace.definedNames.values; |
| library.entryPoint = exportedElements.firstWhere( |
| (element) => element is FunctionElement && element.isEntryPoint, |
| orElse: () => null); |
| } |
| // |
| // Record outputs. |
| // |
| outputs[LIBRARY_ELEMENT4] = library; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given library [libSource]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{ |
| LIBRARY_INPUT: LIBRARY_ELEMENT3.of(libSource), |
| 'exportsLibraryPublicNamespace': |
| EXPORT_SOURCE_CLOSURE.of(libSource).toMapOf(LIBRARY_ELEMENT3) |
| }; |
| } |
| |
| /** |
| * Create a [BuildExportNamespaceTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildExportNamespaceTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildExportNamespaceTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [RESOLVED_UNIT3] for a unit. |
| */ |
| class BuildFunctionTypeAliasesTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [TYPE_PROVIDER] input. |
| */ |
| static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| |
| /** |
| * The name of the [LIBRARY_ELEMENT4] input. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The name of the [RESOLVED_UNIT2] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildFunctionTypeAliasesTask', createTask, buildInputs, |
| <ResultDescriptor>[BUILD_FUNCTION_TYPE_ALIASES_ERRORS, RESOLVED_UNIT3]); |
| |
| BuildFunctionTypeAliasesTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| // |
| // Prepare inputs. |
| // |
| Source source = getRequiredSource(); |
| TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT); |
| // |
| // Resolve FunctionTypeAlias declarations. |
| // |
| TypeResolverVisitor visitor = new TypeResolverVisitor.con2( |
| libraryElement, source, typeProvider, errorListener); |
| for (CompilationUnitMember member in unit.declarations) { |
| if (member is FunctionTypeAlias) { |
| member.accept(visitor); |
| } |
| } |
| // |
| // Record outputs. |
| // |
| outputs[BUILD_FUNCTION_TYPE_ALIASES_ERRORS] = errorListener.errors; |
| outputs[RESOLVED_UNIT3] = unit; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{ |
| TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request), |
| 'importsExportNamespace': |
| IMPORTED_LIBRARIES.of(target.library).toMapOf(LIBRARY_ELEMENT4), |
| LIBRARY_INPUT: LIBRARY_ELEMENT4.of(target.library), |
| UNIT_INPUT: RESOLVED_UNIT2.of(target) |
| }; |
| } |
| |
| /** |
| * Create a [BuildFunctionTypeAliasesTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildFunctionTypeAliasesTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildFunctionTypeAliasesTask(context, target); |
| } |
| } |
| |
| /** |
| * This task finishes building [LIBRARY_ELEMENT] by forcing building |
| * constructors for classes in the defining and part units of a library. |
| */ |
| class BuildLibraryConstructorsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [LIBRARY_ELEMENT5] input. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildLibraryConstructorsTask', createTask, buildInputs, |
| <ResultDescriptor>[LIBRARY_ELEMENT]); |
| |
| BuildLibraryConstructorsTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| LibraryElement library = getRequiredInput(LIBRARY_INPUT); |
| outputs[LIBRARY_ELEMENT] = library; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{ |
| LIBRARY_INPUT: LIBRARY_ELEMENT5.of(libSource), |
| 'resolvedConstructors': |
| CLASS_ELEMENTS.of(libSource).toListOf(CONSTRUCTORS), |
| }; |
| } |
| |
| /** |
| * Create a [BuildLibraryConstructorsTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildLibraryConstructorsTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildLibraryConstructorsTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds a library element for a Dart library. |
| */ |
| class BuildLibraryElementTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input whose value is the defining [RESOLVED_UNIT1]. |
| */ |
| static const String DEFINING_UNIT_INPUT = 'DEFINING_UNIT_INPUT'; |
| |
| /** |
| * The name of the input whose value is a list of built [RESOLVED_UNIT1]s |
| * of the parts sourced by a library. |
| */ |
| static const String PARTS_UNIT_INPUT = 'PARTS_UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildLibraryElementTask', createTask, buildInputs, <ResultDescriptor>[ |
| BUILD_LIBRARY_ERRORS, |
| CLASS_ELEMENTS, |
| LIBRARY_ELEMENT1, |
| IS_LAUNCHABLE |
| ]); |
| |
| /** |
| * The constant used as an unknown common library name in parts. |
| */ |
| static const String _UNKNOWN_LIBRARY_NAME = 'unknown-library-name'; |
| |
| /** |
| * Initialize a newly created task to build a library element for the given |
| * [target] in the given [context]. |
| */ |
| BuildLibraryElementTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| List<AnalysisError> errors = <AnalysisError>[]; |
| // |
| // Prepare inputs. |
| // |
| Source librarySource = getRequiredSource(); |
| CompilationUnit definingCompilationUnit = |
| getRequiredInput(DEFINING_UNIT_INPUT); |
| List<CompilationUnit> partUnits = getRequiredInput(PARTS_UNIT_INPUT); |
| // |
| // Process inputs. |
| // |
| CompilationUnitElementImpl definingCompilationUnitElement = |
| definingCompilationUnit.element; |
| Map<Source, CompilationUnit> partUnitMap = |
| new HashMap<Source, CompilationUnit>(); |
| for (CompilationUnit partUnit in partUnits) { |
| Source partSource = partUnit.element.source; |
| partUnitMap[partSource] = partUnit; |
| } |
| // |
| // Update "part" directives. |
| // |
| LibraryIdentifier libraryNameNode = null; |
| String partsLibraryName = _UNKNOWN_LIBRARY_NAME; |
| bool hasPartDirective = false; |
| FunctionElement entryPoint = |
| _findEntryPoint(definingCompilationUnitElement); |
| List<Directive> directivesToResolve = <Directive>[]; |
| List<CompilationUnitElementImpl> sourcedCompilationUnits = |
| <CompilationUnitElementImpl>[]; |
| for (Directive directive in definingCompilationUnit.directives) { |
| if (directive is LibraryDirective) { |
| if (libraryNameNode == null) { |
| libraryNameNode = directive.name; |
| directivesToResolve.add(directive); |
| } |
| } else if (directive is PartDirective) { |
| PartDirective partDirective = directive; |
| StringLiteral partUri = partDirective.uri; |
| Source partSource = partDirective.source; |
| if (context.exists(partSource)) { |
| hasPartDirective = true; |
| CompilationUnit partUnit = partUnitMap[partSource]; |
| CompilationUnitElementImpl partElement = partUnit.element; |
| partElement.uriOffset = partUri.offset; |
| partElement.uriEnd = partUri.end; |
| partElement.uri = partDirective.uriContent; |
| // |
| // Validate that the part contains a part-of directive with the same |
| // name as the library. |
| // |
| String partLibraryName = |
| _getPartLibraryName(partSource, partUnit, directivesToResolve); |
| if (partLibraryName == null) { |
| errors.add(new AnalysisError.con2(librarySource, partUri.offset, |
| partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, |
| [partUri.toSource()])); |
| } else if (libraryNameNode == null) { |
| if (partsLibraryName == _UNKNOWN_LIBRARY_NAME) { |
| partsLibraryName = partLibraryName; |
| } else if (partsLibraryName != partLibraryName) { |
| partsLibraryName = null; |
| } |
| } else if (libraryNameNode.name != partLibraryName) { |
| errors.add(new AnalysisError.con2(librarySource, partUri.offset, |
| partUri.length, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [ |
| libraryNameNode.name, |
| partLibraryName |
| ])); |
| } |
| if (entryPoint == null) { |
| entryPoint = _findEntryPoint(partElement); |
| } |
| directive.element = partElement; |
| sourcedCompilationUnits.add(partElement); |
| } |
| } |
| } |
| if (hasPartDirective && libraryNameNode == null) { |
| AnalysisError error; |
| if (partsLibraryName != _UNKNOWN_LIBRARY_NAME && |
| partsLibraryName != null) { |
| error = new AnalysisErrorWithProperties.con1(librarySource, |
| ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART) |
| ..setProperty(ErrorProperty.PARTS_LIBRARY_NAME, partsLibraryName); |
| } else { |
| error = new AnalysisError.con1(librarySource, |
| ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART); |
| } |
| errors.add(error); |
| } |
| // |
| // Create and populate the library element. |
| // |
| LibraryElementImpl libraryElement = |
| new LibraryElementImpl.forNode(context, libraryNameNode); |
| libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
| libraryElement.entryPoint = entryPoint; |
| libraryElement.parts = sourcedCompilationUnits; |
| for (Directive directive in directivesToResolve) { |
| directive.element = libraryElement; |
| } |
| if (sourcedCompilationUnits.isNotEmpty) { |
| _patchTopLevelAccessors(libraryElement); |
| } |
| // |
| // Prepare all class elements. |
| // |
| List<ClassElement> classElements = libraryElement.units |
| .map((CompilationUnitElement unitElement) => unitElement.types) |
| .expand((List<ClassElement> unitClassElements) => unitClassElements) |
| .toList(); |
| // |
| // Record outputs. |
| // |
| outputs[BUILD_LIBRARY_ERRORS] = errors; |
| outputs[CLASS_ELEMENTS] = classElements; |
| outputs[LIBRARY_ELEMENT1] = libraryElement; |
| outputs[IS_LAUNCHABLE] = entryPoint != null; |
| } |
| |
| /** |
| * Add all of the non-synthetic [getters] and [setters] defined in the given |
| * [unit] that have no corresponding accessor to one of the given collections. |
| */ |
| void _collectAccessors(Map<String, PropertyAccessorElement> getters, |
| List<PropertyAccessorElement> setters, CompilationUnitElement unit) { |
| for (PropertyAccessorElement accessor in unit.accessors) { |
| if (accessor.isGetter) { |
| if (!accessor.isSynthetic && accessor.correspondingSetter == null) { |
| getters[accessor.displayName] = accessor; |
| } |
| } else { |
| if (!accessor.isSynthetic && accessor.correspondingGetter == null) { |
| setters.add(accessor); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Return the top-level [FunctionElement] entry point, or `null` if the given |
| * [element] does not define an entry point. |
| */ |
| FunctionElement _findEntryPoint(CompilationUnitElementImpl element) { |
| for (FunctionElement function in element.functions) { |
| if (function.isEntryPoint) { |
| return function; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return the name of the library that the given part is declared to be a |
| * part of, or `null` if the part does not contain a part-of directive. |
| */ |
| String _getPartLibraryName(Source partSource, CompilationUnit partUnit, |
| List<Directive> directivesToResolve) { |
| for (Directive directive in partUnit.directives) { |
| if (directive is PartOfDirective) { |
| directivesToResolve.add(directive); |
| LibraryIdentifier libraryName = directive.libraryName; |
| if (libraryName != null) { |
| return libraryName.name; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Look through all of the compilation units defined for the given [library], |
| * looking for getters and setters that are defined in different compilation |
| * units but that have the same names. If any are found, make sure that they |
| * have the same variable element. |
| */ |
| void _patchTopLevelAccessors(LibraryElementImpl library) { |
| HashMap<String, PropertyAccessorElement> getters = |
| new HashMap<String, PropertyAccessorElement>(); |
| List<PropertyAccessorElement> setters = <PropertyAccessorElement>[]; |
| _collectAccessors(getters, setters, library.definingCompilationUnit); |
| for (CompilationUnitElement unit in library.parts) { |
| _collectAccessors(getters, setters, unit); |
| } |
| for (PropertyAccessorElementImpl setter in setters) { |
| PropertyAccessorElement getter = getters[setter.displayName]; |
| if (getter != null) { |
| TopLevelVariableElementImpl variable = getter.variable; |
| TopLevelVariableElementImpl setterVariable = setter.variable; |
| CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement; |
| setterUnit.replaceTopLevelVariable(setterVariable, variable); |
| variable.setter = setter; |
| setter.variable = variable; |
| } |
| } |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the given |
| * [libSource]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{ |
| DEFINING_UNIT_INPUT: |
| RESOLVED_UNIT1.of(new LibraryUnitTarget(libSource, libSource)), |
| PARTS_UNIT_INPUT: INCLUDED_PARTS.of(libSource).toList((Source unit) { |
| LibraryUnitTarget lut = new LibraryUnitTarget(libSource, unit); |
| return RESOLVED_UNIT1.of(lut); |
| }) |
| }; |
| } |
| |
| /** |
| * Create a [BuildLibraryElementTask] based on the given [target] in the |
| * given [context]. |
| */ |
| static BuildLibraryElementTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildLibraryElementTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [PUBLIC_NAMESPACE] for a library. |
| */ |
| class BuildPublicNamespaceTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input for [LIBRARY_ELEMENT2] of a library. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildPublicNamespaceTask', createTask, buildInputs, |
| <ResultDescriptor>[LIBRARY_ELEMENT3]); |
| |
| BuildPublicNamespaceTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| LibraryElementImpl library = getRequiredInput(LIBRARY_INPUT); |
| library.publicNamespace = new PublicNamespaceBuilder().build(library); |
| outputs[LIBRARY_ELEMENT3] = library; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given library [libSource]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{LIBRARY_INPUT: LIBRARY_ELEMENT2.of(libSource)}; |
| } |
| |
| /** |
| * Create a [BuildPublicNamespaceTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildPublicNamespaceTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildPublicNamespaceTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [IMPORT_SOURCE_CLOSURE] and [EXPORT_SOURCE_CLOSURE] of |
| * a library. |
| */ |
| class BuildSourceClosuresTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the import closure. |
| */ |
| static const String IMPORT_CLOSURE_INPUT = 'IMPORT_CLOSURE_INPUT'; |
| |
| /** |
| * The name of the export closure. |
| */ |
| static const String EXPORT_CLOSURE_INPUT = 'EXPORT_CLOSURE_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildExportSourceClosureTask', createTask, buildInputs, |
| <ResultDescriptor>[ |
| IMPORT_SOURCE_CLOSURE, |
| EXPORT_SOURCE_CLOSURE, |
| IS_CLIENT |
| ]); |
| |
| BuildSourceClosuresTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| List<Source> importClosure = getRequiredInput(IMPORT_CLOSURE_INPUT); |
| List<Source> exportClosure = getRequiredInput(EXPORT_CLOSURE_INPUT); |
| Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML); |
| // |
| // Record outputs. |
| // |
| outputs[IMPORT_SOURCE_CLOSURE] = importClosure; |
| outputs[EXPORT_SOURCE_CLOSURE] = exportClosure; |
| outputs[IS_CLIENT] = importClosure.contains(htmlSource); |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given library [libSource]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{ |
| IMPORT_CLOSURE_INPUT: new _ImportSourceClosureTaskInput(libSource), |
| EXPORT_CLOSURE_INPUT: new _ExportSourceClosureTaskInput(libSource) |
| }; |
| } |
| |
| /** |
| * Create a [BuildSourceClosuresTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static BuildSourceClosuresTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new BuildSourceClosuresTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [TYPE_PROVIDER] for a context. |
| */ |
| class BuildTypeProviderTask extends SourceBasedAnalysisTask { |
| /** |
| * The [PUBLIC_NAMESPACE] input of the `dart:core` library. |
| */ |
| static const String CORE_INPUT = 'CORE_INPUT'; |
| |
| /** |
| * The [PUBLIC_NAMESPACE] input of the `dart:async` library. |
| */ |
| static const String ASYNC_INPUT = 'ASYNC_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'BuildTypeProviderTask', createTask, buildInputs, |
| <ResultDescriptor>[TYPE_PROVIDER]); |
| |
| BuildTypeProviderTask( |
| InternalAnalysisContext context, AnalysisContextTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| LibraryElement coreLibrary = getRequiredInput(CORE_INPUT); |
| LibraryElement asyncLibrary = getRequiredInput(ASYNC_INPUT); |
| Namespace coreNamespace = coreLibrary.publicNamespace; |
| Namespace asyncNamespace = asyncLibrary.publicNamespace; |
| // |
| // Record outputs. |
| // |
| TypeProvider typeProvider = |
| new TypeProviderImpl.forNamespaces(coreNamespace, asyncNamespace); |
| (context as ExtendedAnalysisContext).typeProvider = typeProvider; |
| outputs[TYPE_PROVIDER] = typeProvider; |
| } |
| |
| static Map<String, TaskInput> buildInputs(AnalysisContextTarget target) { |
| SourceFactory sourceFactory = target.context.sourceFactory; |
| Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE); |
| Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC); |
| return <String, TaskInput>{ |
| CORE_INPUT: LIBRARY_ELEMENT3.of(coreSource), |
| ASYNC_INPUT: LIBRARY_ELEMENT3.of(asyncSource) |
| }; |
| } |
| |
| /** |
| * Create a [BuildTypeProviderTask] based on the given [context]. |
| */ |
| static BuildTypeProviderTask createTask( |
| AnalysisContext context, AnalysisContextTarget target) { |
| return new BuildTypeProviderTask(context, target); |
| } |
| } |
| |
| /** |
| * The helper for building the export [Namespace] of a [LibraryElement]. |
| */ |
| class ExportNamespaceBuilder { |
| /** |
| * Build the export [Namespace] of the given [LibraryElement]. |
| */ |
| Namespace build(LibraryElement library) { |
| return new Namespace( |
| _createExportMapping(library, new HashSet<LibraryElement>())); |
| } |
| |
| /** |
| * Create a mapping table representing the export namespace of the given |
| * [library]. |
| * |
| * The given [visitedElements] a set of libraries that do not need to be |
| * visited when processing the export directives of the given library because |
| * all of the names defined by them will be added by another library. |
| */ |
| HashMap<String, Element> _createExportMapping( |
| LibraryElement library, HashSet<LibraryElement> visitedElements) { |
| visitedElements.add(library); |
| try { |
| HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| // Add names of the export directives. |
| for (ExportElement element in library.exports) { |
| LibraryElement exportedLibrary = element.exportedLibrary; |
| if (exportedLibrary != null && |
| !visitedElements.contains(exportedLibrary)) { |
| // |
| // The exported library will be null if the URI does not reference a |
| // valid library. |
| // |
| HashMap<String, Element> exportedNames = |
| _createExportMapping(exportedLibrary, visitedElements); |
| exportedNames = _applyCombinators(exportedNames, element.combinators); |
| definedNames.addAll(exportedNames); |
| } |
| } |
| // Add names of the public namespace. |
| { |
| Namespace publicNamespace = library.publicNamespace; |
| if (publicNamespace != null) { |
| definedNames.addAll(publicNamespace.definedNames); |
| } |
| } |
| return definedNames; |
| } finally { |
| visitedElements.remove(library); |
| } |
| } |
| |
| /** |
| * Apply the given [combinators] to all of the names in [definedNames]. |
| */ |
| static HashMap<String, Element> _applyCombinators( |
| HashMap<String, Element> definedNames, |
| List<NamespaceCombinator> combinators) { |
| for (NamespaceCombinator combinator in combinators) { |
| if (combinator is HideElementCombinator) { |
| _hide(definedNames, combinator.hiddenNames); |
| } else if (combinator is ShowElementCombinator) { |
| definedNames = _show(definedNames, combinator.shownNames); |
| } |
| } |
| return definedNames; |
| } |
| |
| /** |
| * Hide all of the [hiddenNames] by removing them from the given |
| * [definedNames]. |
| */ |
| static void _hide( |
| HashMap<String, Element> definedNames, List<String> hiddenNames) { |
| for (String name in hiddenNames) { |
| definedNames.remove(name); |
| definedNames.remove('$name='); |
| } |
| } |
| |
| /** |
| * Show only the given [shownNames] by removing all other names from the given |
| * [definedNames]. |
| */ |
| static HashMap<String, Element> _show( |
| HashMap<String, Element> definedNames, List<String> shownNames) { |
| HashMap<String, Element> newNames = new HashMap<String, Element>(); |
| for (String name in shownNames) { |
| Element element = definedNames[name]; |
| if (element != null) { |
| newNames[name] = element; |
| } |
| String setterName = '$name='; |
| element = definedNames[setterName]; |
| if (element != null) { |
| newNames[setterName] = element; |
| } |
| } |
| return newNames; |
| } |
| } |
| |
| /** |
| * A task that builds [USED_IMPORTED_ELEMENTS] for a unit. |
| */ |
| class GatherUsedImportedElementsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [RESOLVED_UNIT] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'GatherUsedImportedElementsTask', createTask, buildInputs, |
| <ResultDescriptor>[USED_IMPORTED_ELEMENTS]); |
| |
| GatherUsedImportedElementsTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| LibraryElement libraryElement = unitElement.library; |
| // |
| // Prepare used imported elements. |
| // |
| GatherUsedImportedElementsVisitor visitor = |
| new GatherUsedImportedElementsVisitor(libraryElement); |
| unit.accept(visitor); |
| // |
| // Record outputs. |
| // |
| outputs[USED_IMPORTED_ELEMENTS] = visitor.usedElements; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)}; |
| } |
| |
| /** |
| * Create a [GatherUsedImportedElementsTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static GatherUsedImportedElementsTask createTask( |
| AnalysisContext context, LibraryUnitTarget target) { |
| return new GatherUsedImportedElementsTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [USED_LOCAL_ELEMENTS] for a unit. |
| */ |
| class GatherUsedLocalElementsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [RESOLVED_UNIT] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'GatherUsedLocalElementsTask', createTask, buildInputs, |
| <ResultDescriptor>[USED_LOCAL_ELEMENTS]); |
| |
| GatherUsedLocalElementsTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| LibraryElement libraryElement = unitElement.library; |
| // |
| // Prepare used local elements. |
| // |
| GatherUsedLocalElementsVisitor visitor = |
| new GatherUsedLocalElementsVisitor(libraryElement); |
| unit.accept(visitor); |
| // |
| // Record outputs. |
| // |
| outputs[USED_LOCAL_ELEMENTS] = visitor.usedElements; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)}; |
| } |
| |
| /** |
| * Create a [GatherUsedLocalElementsTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static GatherUsedLocalElementsTask createTask( |
| AnalysisContext context, LibraryUnitTarget target) { |
| return new GatherUsedLocalElementsTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that generates [HINTS] for a unit. |
| */ |
| class GenerateHintsTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [RESOLVED_UNIT] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input. |
| */ |
| static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS'; |
| |
| /** |
| * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input. |
| */ |
| static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'GenerateHintsTask', createTask, buildInputs, <ResultDescriptor>[HINTS]); |
| |
| GenerateHintsTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| Source source = getRequiredSource(); |
| ErrorReporter errorReporter = new ErrorReporter(errorListener, source); |
| // |
| // Prepare inputs. |
| // |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| List<UsedImportedElements> usedImportedElementsList = |
| getRequiredInput(USED_IMPORTED_ELEMENTS_INPUT); |
| List<UsedLocalElements> usedLocalElementsList = |
| getRequiredInput(USED_LOCAL_ELEMENTS_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| LibraryElement libraryElement = unitElement.library; |
| // |
| // Generate errors. |
| // |
| unit.accept(new DeadCodeVerifier(errorReporter)); |
| // Verify imports. |
| { |
| ImportsVerifier verifier = new ImportsVerifier(); |
| verifier.addImports(unit); |
| usedImportedElementsList.forEach(verifier.removeUsedElements); |
| verifier.generateDuplicateImportHints(errorReporter); |
| verifier.generateUnusedImportHints(errorReporter); |
| } |
| // Unused local elements. |
| { |
| UsedLocalElements usedElements = |
| new UsedLocalElements.merge(usedLocalElementsList); |
| UnusedLocalElementsVerifier visitor = |
| new UnusedLocalElementsVerifier(errorListener, usedElements); |
| unitElement.accept(visitor); |
| } |
| // Dart2js analysis. |
| if (context.analysisOptions.dart2jsHint) { |
| unit.accept(new Dart2JSVerifier(errorReporter)); |
| } |
| // Dart best practices. |
| InheritanceManager inheritanceManager = |
| new InheritanceManager(libraryElement); |
| TypeProvider typeProvider = context.typeProvider; |
| unit.accept(new BestPracticesVerifier(errorReporter, typeProvider)); |
| unit.accept(new OverrideVerifier(errorReporter, inheritanceManager)); |
| // Find to-do comments. |
| new ToDoFinder(errorReporter).findIn(unit); |
| // |
| // Record outputs. |
| // |
| outputs[HINTS] = errorListener.errors; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| Source libSource = target.library; |
| return <String, TaskInput>{ |
| UNIT_INPUT: RESOLVED_UNIT.of(target), |
| USED_LOCAL_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) { |
| LibraryUnitTarget target = new LibraryUnitTarget(libSource, unit); |
| return USED_LOCAL_ELEMENTS.of(target); |
| }), |
| USED_IMPORTED_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) { |
| LibraryUnitTarget target = new LibraryUnitTarget(libSource, unit); |
| return USED_IMPORTED_ELEMENTS.of(target); |
| }) |
| }; |
| } |
| |
| /** |
| * Create a [GenerateHintsTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static GenerateHintsTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new GenerateHintsTask(context, target); |
| } |
| } |
| |
| /** |
| * A pair of a library [Source] and a unit [Source] in this library. |
| */ |
| class LibraryUnitTarget implements AnalysisTarget { |
| final Source library; |
| final Source unit; |
| |
| LibraryUnitTarget(this.library, this.unit); |
| |
| @override |
| int get hashCode { |
| return JenkinsSmiHash.combine(library.hashCode, unit.hashCode); |
| } |
| |
| @override |
| Source get source => unit; |
| |
| @override |
| bool operator ==(other) { |
| return other is LibraryUnitTarget && |
| other.library == library && |
| other.unit == unit; |
| } |
| } |
| |
| /** |
| * A task that parses the content of a Dart file, producing an AST structure. |
| */ |
| class ParseDartTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input whose value is the line information produced for the |
| * file. |
| */ |
| static const String LINE_INFO_INPUT_NAME = 'LINE_INFO_INPUT_NAME'; |
| |
| /** |
| * The name of the input whose value is the token stream produced for the file. |
| */ |
| static const String TOKEN_STREAM_INPUT_NAME = 'TOKEN_STREAM_INPUT_NAME'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('ParseDartTask', |
| createTask, buildInputs, <ResultDescriptor>[ |
| EXPORTED_LIBRARIES, |
| IMPORTED_LIBRARIES, |
| INCLUDED_PARTS, |
| PARSE_ERRORS, |
| PARSED_UNIT, |
| SOURCE_KIND, |
| UNITS |
| ]); |
| |
| /** |
| * Initialize a newly created task to parse the content of the Dart file |
| * associated with the given [target] in the given [context]. |
| */ |
| ParseDartTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| Source source = getRequiredSource(); |
| LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT_NAME); |
| Token tokenStream = getRequiredInput(TOKEN_STREAM_INPUT_NAME); |
| |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| Parser parser = new Parser(source, errorListener); |
| AnalysisOptions options = context.analysisOptions; |
| parser.parseFunctionBodies = options.analyzeFunctionBodiesPredicate(source); |
| CompilationUnit unit = parser.parseCompilationUnit(tokenStream); |
| unit.lineInfo = lineInfo; |
| |
| bool hasNonPartOfDirective = false; |
| bool hasPartOfDirective = false; |
| HashSet<Source> exportedSources = new HashSet<Source>(); |
| HashSet<Source> importedSources = new HashSet<Source>(); |
| HashSet<Source> includedSources = new HashSet<Source>(); |
| for (Directive directive in unit.directives) { |
| if (directive is PartOfDirective) { |
| hasPartOfDirective = true; |
| } else { |
| hasNonPartOfDirective = true; |
| if (directive is UriBasedDirective) { |
| Source referencedSource = |
| resolveDirective(context, source, directive, errorListener); |
| if (referencedSource != null) { |
| if (directive is ExportDirective) { |
| exportedSources.add(referencedSource); |
| } else if (directive is ImportDirective) { |
| importedSources.add(referencedSource); |
| } else if (directive is PartDirective) { |
| if (referencedSource != source) { |
| includedSources.add(referencedSource); |
| } |
| } else { |
| throw new AnalysisException( |
| '$runtimeType failed to handle a ${directive.runtimeType}'); |
| } |
| } |
| } |
| } |
| } |
| // |
| // Always include "dart:core" source. |
| // |
| Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE); |
| importedSources.add(coreLibrarySource); |
| // |
| // Compute kind. |
| // |
| SourceKind sourceKind = SourceKind.LIBRARY; |
| if (!hasNonPartOfDirective && hasPartOfDirective) { |
| sourceKind = SourceKind.PART; |
| } |
| // |
| // Record outputs. |
| // |
| outputs[EXPORTED_LIBRARIES] = exportedSources.toList(); |
| outputs[IMPORTED_LIBRARIES] = importedSources.toList(); |
| outputs[INCLUDED_PARTS] = includedSources.toList(); |
| outputs[PARSE_ERRORS] = errorListener.getErrorsForSource(source); |
| outputs[PARSED_UNIT] = unit; |
| outputs[SOURCE_KIND] = sourceKind; |
| outputs[UNITS] = <Source>[source]..addAll(includedSources); |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the given |
| * [source]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source source) { |
| return <String, TaskInput>{ |
| LINE_INFO_INPUT_NAME: LINE_INFO.of(source), |
| TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(source) |
| }; |
| } |
| |
| /** |
| * Create a [ParseDartTask] based on the given [target] in the given |
| * [context]. |
| */ |
| static ParseDartTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ParseDartTask(context, target); |
| } |
| |
| /** |
| * Return the result of resolving the URI of the given URI-based [directive] |
| * against the URI of the given library, or `null` if the URI is not valid. |
| * |
| * Resolution is to be performed in the given [context]. Errors should be |
| * reported to the [errorListener]. |
| */ |
| static Source resolveDirective(AnalysisContext context, Source librarySource, |
| UriBasedDirective directive, AnalysisErrorListener errorListener) { |
| StringLiteral uriLiteral = directive.uri; |
| String uriContent = uriLiteral.stringValue; |
| if (uriContent != null) { |
| uriContent = uriContent.trim(); |
| directive.uriContent = uriContent; |
| } |
| UriValidationCode code = directive.validate(); |
| if (code == null) { |
| String encodedUriContent = Uri.encodeFull(uriContent); |
| Source source = |
| context.sourceFactory.resolveUri(librarySource, encodedUriContent); |
| directive.source = source; |
| return source; |
| } |
| if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) { |
| return null; |
| } |
| if (code == UriValidationCode.URI_WITH_INTERPOLATION) { |
| errorListener.onError(new AnalysisError.con2(librarySource, |
| uriLiteral.offset, uriLiteral.length, |
| CompileTimeErrorCode.URI_WITH_INTERPOLATION)); |
| return null; |
| } |
| if (code == UriValidationCode.INVALID_URI) { |
| errorListener.onError(new AnalysisError.con2(librarySource, |
| uriLiteral.offset, uriLiteral.length, |
| CompileTimeErrorCode.INVALID_URI, [uriContent])); |
| return null; |
| } |
| throw new AnalysisException('Failed to handle validation code: $code'); |
| } |
| } |
| |
| /** |
| * The helper for building the public [Namespace] of a [LibraryElement]. |
| */ |
| class PublicNamespaceBuilder { |
| final HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| |
| /** |
| * Build a public [Namespace] of the given [library]. |
| */ |
| Namespace build(LibraryElement library) { |
| definedNames.clear(); |
| _addPublicNames(library.definingCompilationUnit); |
| library.parts.forEach(_addPublicNames); |
| return new Namespace(definedNames); |
| } |
| |
| /** |
| * Add the given [element] if it has a publicly visible name. |
| */ |
| void _addIfPublic(Element element) { |
| String name = element.name; |
| if (name != null && !Scope.isPrivateName(name)) { |
| definedNames[name] = element; |
| } |
| } |
| |
| /** |
| * Add all of the public top-level names that are defined in the given |
| * [compilationUnit]. |
| */ |
| void _addPublicNames(CompilationUnitElement compilationUnit) { |
| compilationUnit.accessors.forEach(_addIfPublic); |
| compilationUnit.enums.forEach(_addIfPublic); |
| compilationUnit.functions.forEach(_addIfPublic); |
| compilationUnit.functionTypeAliases.forEach(_addIfPublic); |
| compilationUnit.types.forEach(_addIfPublic); |
| } |
| } |
| |
| /** |
| * An artifitial task that does nothing except to force type names resolution |
| * for the defining and part units of a library. |
| */ |
| class ResolveLibraryTypeNamesTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [LIBRARY_ELEMENT4] input. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'ResolveLibraryTypeNamesTask', createTask, buildInputs, |
| <ResultDescriptor>[LIBRARY_ELEMENT5]); |
| |
| ResolveLibraryTypeNamesTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| LibraryElement library = getRequiredInput(LIBRARY_INPUT); |
| outputs[LIBRARY_ELEMENT5] = library; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source libSource) { |
| return <String, TaskInput>{ |
| LIBRARY_INPUT: LIBRARY_ELEMENT4.of(libSource), |
| 'resolvedUnits': IMPORT_SOURCE_CLOSURE |
| .of(libSource) |
| .toMapOf(UNITS) |
| .toFlattenList((Source library, Source unit) => |
| RESOLVED_UNIT4.of(new LibraryUnitTarget(library, unit))) |
| }; |
| } |
| |
| /** |
| * Create a [ResolveLibraryTypeNamesTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static ResolveLibraryTypeNamesTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ResolveLibraryTypeNamesTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [RESOLVED_UNIT] for a unit. |
| */ |
| class ResolveReferencesTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [LIBRARY_ELEMENT] input. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The name of the [RESOLVED_UNIT5] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'ResolveReferencesTask', createTask, buildInputs, |
| <ResultDescriptor>[RESOLVED_UNIT]); |
| |
| ResolveReferencesTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| // |
| // Prepare inputs. |
| // |
| LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT); |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| TypeProvider typeProvider = unitElement.context.typeProvider; |
| // |
| // Resolve references. |
| // |
| InheritanceManager inheritanceManager = |
| new InheritanceManager(libraryElement); |
| AstVisitor visitor = new ResolverVisitor.con2(libraryElement, |
| unitElement.source, typeProvider, inheritanceManager, errorListener); |
| unit.accept(visitor); |
| // |
| // Record outputs. |
| // |
| outputs[RESOLVE_REFERENCES_ERRORS] = errorListener.errors; |
| outputs[RESOLVED_UNIT] = unit; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{ |
| LIBRARY_INPUT: LIBRARY_ELEMENT.of(target.library), |
| UNIT_INPUT: RESOLVED_UNIT5.of(target) |
| }; |
| } |
| |
| /** |
| * Create a [ResolveReferencesTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static ResolveReferencesTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ResolveReferencesTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [RESOLVED_UNIT4] for a unit. |
| */ |
| class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [RESOLVED_UNIT3] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'ResolveUnitTypeNamesTask', createTask, buildInputs, <ResultDescriptor>[ |
| RESOLVE_TYPE_NAMES_ERRORS, |
| RESOLVED_UNIT4 |
| ]); |
| |
| ResolveUnitTypeNamesTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| // |
| // Prepare inputs. |
| // |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| // |
| // Resolve TypeName nodes. |
| // |
| TypeResolverVisitor visitor = new TypeResolverVisitor.con2( |
| unitElement.library, unitElement.source, context.typeProvider, |
| errorListener); |
| unit.accept(visitor); |
| // |
| // Record outputs. |
| // |
| outputs[RESOLVE_TYPE_NAMES_ERRORS] = errorListener.errors; |
| outputs[RESOLVED_UNIT4] = unit; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT3.of(target)}; |
| } |
| |
| /** |
| * Create a [ResolveUnitTypeNamesTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static ResolveUnitTypeNamesTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ResolveUnitTypeNamesTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [RESOLVED_UNIT5] for a unit. |
| */ |
| class ResolveVariableReferencesTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [LIBRARY_ELEMENT] input. |
| */ |
| static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| |
| /** |
| * The name of the [RESOLVED_UNIT4] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 'ResolveVariableReferencesTask', createTask, buildInputs, |
| <ResultDescriptor>[RESOLVED_UNIT5]); |
| |
| ResolveVariableReferencesTask( |
| InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| // |
| // Prepare inputs. |
| // |
| LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT); |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| // |
| // Resolve local variables. |
| // |
| TypeProvider typeProvider = unitElement.context.typeProvider; |
| Scope nameScope = new LibraryScope(libraryElement, errorListener); |
| AstVisitor visitor = new VariableResolverVisitor.con2(libraryElement, |
| unitElement.source, typeProvider, nameScope, errorListener); |
| unit.accept(visitor); |
| // |
| // Record outputs. |
| // |
| outputs[RESOLVED_UNIT5] = unit; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{ |
| LIBRARY_INPUT: LIBRARY_ELEMENT.of(target.library), |
| UNIT_INPUT: RESOLVED_UNIT4.of(target) |
| }; |
| } |
| |
| /** |
| * Create a [ResolveVariableReferencesTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static ResolveVariableReferencesTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ResolveVariableReferencesTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that scans the content of a file, producing a set of Dart tokens. |
| */ |
| class ScanDartTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the input whose value is the content of the file. |
| */ |
| static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('ScanDartTask', |
| createTask, buildInputs, <ResultDescriptor>[ |
| LINE_INFO, |
| SCAN_ERRORS, |
| TOKEN_STREAM |
| ]); |
| |
| /** |
| * Initialize a newly created task to access the content of the source |
| * associated with the given [target] in the given [context]. |
| */ |
| ScanDartTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| Source source = getRequiredSource(); |
| String content = getRequiredInput(CONTENT_INPUT_NAME); |
| |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| Scanner scanner = |
| new Scanner(source, new CharSequenceReader(content), errorListener); |
| scanner.preserveComments = context.analysisOptions.preserveComments; |
| scanner.enableNullAwareOperators = |
| context.analysisOptions.enableNullAwareOperators; |
| outputs[TOKEN_STREAM] = scanner.tokenize(); |
| outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); |
| outputs[SCAN_ERRORS] = errorListener.getErrorsForSource(source); |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the given |
| * [source]. |
| */ |
| static Map<String, TaskInput> buildInputs(Source source) { |
| return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)}; |
| } |
| |
| /** |
| * Create a [ScanDartTask] based on the given [target] in the given [context]. |
| */ |
| static ScanDartTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new ScanDartTask(context, target); |
| } |
| } |
| |
| /** |
| * A task that builds [VERIFY_ERRORS] for a unit. |
| */ |
| class VerifyUnitTask extends SourceBasedAnalysisTask { |
| /** |
| * The name of the [RESOLVED_UNIT] input. |
| */ |
| static const String UNIT_INPUT = 'UNIT_INPUT'; |
| |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('VerifyUnitTask', |
| createTask, buildInputs, <ResultDescriptor>[VERIFY_ERRORS]); |
| |
| /** |
| * The [ErrorReporter] to report errors to. |
| */ |
| ErrorReporter errorReporter; |
| |
| VerifyUnitTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| |
| @override |
| TaskDescriptor get descriptor => DESCRIPTOR; |
| |
| @override |
| void internalPerform() { |
| RecordingErrorListener errorListener = new RecordingErrorListener(); |
| Source source = getRequiredSource(); |
| errorReporter = new ErrorReporter(errorListener, source); |
| TypeProvider typeProvider = context.typeProvider; |
| // |
| // Prepare inputs. |
| // |
| CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| CompilationUnitElement unitElement = unit.element; |
| LibraryElement libraryElement = unitElement.library; |
| // |
| // Use the ErrorVerifier to compute errors. |
| // |
| ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter, |
| libraryElement, typeProvider, new InheritanceManager(libraryElement)); |
| unit.accept(errorVerifier); |
| // |
| // Record outputs. |
| // |
| outputs[VERIFY_ERRORS] = errorListener.errors; |
| } |
| |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| * given [target]. |
| */ |
| static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) { |
| return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)}; |
| } |
| |
| /** |
| * Create a [VerifyUnitTask] based on the given [target] in |
| * the given [context]. |
| */ |
| static VerifyUnitTask createTask( |
| AnalysisContext context, AnalysisTarget target) { |
| return new VerifyUnitTask(context, target); |
| } |
| } |
| |
| /** |
| * A [TaskInput] whose value is a list of library sources exported directly |
| * or indirectly by the target [Source]. |
| */ |
| class _ExportSourceClosureTaskInput implements TaskInput<List<Source>> { |
| final Source target; |
| |
| _ExportSourceClosureTaskInput(this.target); |
| |
| @override |
| TaskInputBuilder<List<Source>> createBuilder() => |
| new _SourceClosureTaskInputBuilder(target, _SourceClosureKind.EXPORT); |
| } |
| |
| /** |
| * The kind of the source closure to build. |
| */ |
| enum _SourceClosureKind { IMPORT, EXPORT } |
| |
| /** |
| * A [TaskInput] whose value is a list of library sources imported directly |
| * or indirectly by the target [Source]. |
| */ |
| class _ImportSourceClosureTaskInput implements TaskInput<List<Source>> { |
| final Source target; |
| |
| _ImportSourceClosureTaskInput(this.target); |
| |
| @override |
| TaskInputBuilder<List<Source>> createBuilder() => |
| new _SourceClosureTaskInputBuilder(target, _SourceClosureKind.IMPORT); |
| } |
| |
| /** |
| * A [TaskInputBuilder] to build values for [_ImportSourceClosureTaskInput]. |
| */ |
| class _SourceClosureTaskInputBuilder implements TaskInputBuilder<List<Source>> { |
| final _SourceClosureKind kind; |
| final Set<LibraryElement> _libraries = new HashSet<LibraryElement>(); |
| final Set<Source> _newSources = new HashSet<Source>(); |
| |
| Source currentTarget; |
| |
| _SourceClosureTaskInputBuilder(Source librarySource, this.kind) { |
| _newSources.add(librarySource); |
| } |
| |
| @override |
| ResultDescriptor get currentResult => LIBRARY_ELEMENT2; |
| |
| @override |
| void set currentValue(LibraryElement library) { |
| if (_libraries.add(library)) { |
| if (kind == _SourceClosureKind.IMPORT) { |
| for (ImportElement importElement in library.imports) { |
| Source importedSource = importElement.importedLibrary.source; |
| _newSources.add(importedSource); |
| } |
| } else { |
| for (ExportElement exportElement in library.exports) { |
| Source importedSource = exportElement.exportedLibrary.source; |
| _newSources.add(importedSource); |
| } |
| } |
| } |
| } |
| |
| @override |
| List<Source> get inputValue { |
| return _libraries.map((LibraryElement library) => library.source).toList(); |
| } |
| |
| @override |
| bool moveNext() { |
| if (_newSources.isEmpty) { |
| return false; |
| } |
| currentTarget = _newSources.first; |
| _newSources.remove(currentTarget); |
| return true; |
| } |
| } |