Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(993)

Unified Diff: mojo/public/dart/third_party/analyzer/lib/src/task/dart.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: mojo/public/dart/third_party/analyzer/lib/src/task/dart.dart
diff --git a/mojo/public/dart/third_party/analyzer/lib/src/task/dart.dart b/mojo/public/dart/third_party/analyzer/lib/src/task/dart.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2a0815c95129c49f673bd02319741249d6c2a5ee
--- /dev/null
+++ b/mojo/public/dart/third_party/analyzer/lib/src/task/dart.dart
@@ -0,0 +1,3959 @@
+// 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 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart'
+ hide AnalysisCache, AnalysisTask;
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
+import 'package:analyzer/src/generated/incremental_resolver.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/task/driver.dart';
+import 'package:analyzer/src/task/general.dart';
+import 'package:analyzer/src/task/html.dart';
+import 'package:analyzer/src/task/inputs.dart';
+import 'package:analyzer/src/task/model.dart';
+import 'package:analyzer/src/task/strong_mode.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/general.dart';
+import 'package:analyzer/task/model.dart';
+
+/**
+ * The [ResultCachingPolicy] for ASTs.
+ */
+const ResultCachingPolicy AST_CACHING_POLICY =
+ const SimpleResultCachingPolicy(8192, 8192);
+
+/**
+ * The [ResultCachingPolicy] for [Element]s.
+ */
+const ResultCachingPolicy ELEMENT_CACHING_POLICY =
+ const SimpleResultCachingPolicy(-1, -1);
+
+/**
+ * The [ResultCachingPolicy] for [TOKEN_STREAM].
+ */
+const ResultCachingPolicy TOKEN_STREAM_CACHING_POLICY =
+ const SimpleResultCachingPolicy(1, 1);
+
+/**
+ * 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 [Source]s representing a library.
+ */
+final ListResultDescriptor<AnalysisError> BUILD_DIRECTIVES_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'BUILD_DIRECTIVES_ERRORS', AnalysisError.NO_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 [Source]s representing a library.
+ */
+final ListResultDescriptor<AnalysisError> BUILD_LIBRARY_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'BUILD_LIBRARY_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * A list of the [ClassElement]s representing the classes defined in a
+ * compilation unit.
+ *
+ * The result is only available for [LibrarySpecificUnit]s, and only when strong
+ * mode is enabled.
+ */
+final ListResultDescriptor<ClassElement> CLASSES_IN_UNIT =
+ new ListResultDescriptor<ClassElement>('CLASSES_IN_UNIT', null);
+
+/**
+ * A list of the [ConstantEvaluationTarget]s defined in a unit. This includes
+ * constants defined at top level, statically inside classes, and local to
+ * functions, as well as constant constructors, annotations, and default values
+ * of parameters to constant constructors.
+ */
+final ListResultDescriptor<
+ ConstantEvaluationTarget> COMPILATION_UNIT_CONSTANTS =
+ new ListResultDescriptor<ConstantEvaluationTarget>(
+ 'COMPILATION_UNIT_CONSTANTS', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The element model associated with a single compilation unit.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnitElement> COMPILATION_UNIT_ELEMENT =
+ new ResultDescriptor<CompilationUnitElement>(
+ 'COMPILATION_UNIT_ELEMENT', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The list of [ConstantEvaluationTarget]s on which the target constant element
+ * depends.
+ *
+ * The result is only available for targets representing a
+ * [ConstantEvaluationTarget] (i.e. a constant variable declaration, a constant
+ * constructor, or a parameter element with a default value).
+ */
+final ListResultDescriptor<ConstantEvaluationTarget> CONSTANT_DEPENDENCIES =
+ new ListResultDescriptor<ConstantEvaluationTarget>(
+ 'CONSTANT_DEPENDENCIES', const <ConstantEvaluationTarget>[]);
+
+/**
+ * A [ConstantEvaluationTarget] that has been successfully constant-evaluated.
+ *
+ * TODO(paulberry): is ELEMENT_CACHING_POLICY the correct caching policy?
+ */
+final ResultDescriptor<ConstantEvaluationTarget> CONSTANT_VALUE =
+ new ResultDescriptor<ConstantEvaluationTarget>('CONSTANT_VALUE', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The sources representing the libraries that include a given source as a part.
+ *
+ * The result is only available for [Source]s representing a compilation unit.
+ */
+final ListResultDescriptor<Source> CONTAINING_LIBRARIES =
+ new ListResultDescriptor<Source>('CONTAINING_LIBRARIES', Source.EMPTY_LIST);
+
+/**
+ * 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 [Source]s representing a 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 [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> HINTS =
+ new ListResultDescriptor<AnalysisError>(
+ 'HINT_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * The sources representing the combined import/export closure of a library.
+ * The [Source]s include only library sources, not their units.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ListResultDescriptor<Source> IMPORT_EXPORT_SOURCE_CLOSURE =
+ new ListResultDescriptor<Source>('IMPORT_EXPORT_SOURCE_CLOSURE', null);
+
+/**
+ * A list of the [VariableElement]s whose type should be inferred that another
+ * inferable static variable (the target) depends on.
+ *
+ * The result is only available for [VariableElement]s, and only when strong
+ * mode is enabled.
+ */
+final ListResultDescriptor<
+ VariableElement> INFERABLE_STATIC_VARIABLE_DEPENDENCIES =
+ new ListResultDescriptor<VariableElement>(
+ 'INFERABLE_STATIC_VARIABLE_DEPENDENCIES', null);
+
+/**
+ * A list of the [VariableElement]s defined in a unit whose type should be
+ * inferred. This includes variables defined at the library level as well as
+ * static members inside classes.
+ *
+ * The result is only available for [LibrarySpecificUnit]s, and only when strong
+ * mode is enabled.
+ */
+final ListResultDescriptor<VariableElement> INFERABLE_STATIC_VARIABLES_IN_UNIT =
+ new ListResultDescriptor<VariableElement>(
+ 'INFERABLE_STATIC_VARIABLES_IN_UNIT', null);
+
+/**
+ * An inferrable static variable ([VariableElement]) whose type has been
+ * inferred.
+ */
+final ResultDescriptor<VariableElement> INFERRED_STATIC_VARIABLE =
+ new ResultDescriptor<VariableElement>('INFERRED_STATIC_VARIABLE', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * 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 [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT1 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT1', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * 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 [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT2 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT2', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The partial [LibraryElement] associated with a library.
+ *
+ * In addition to [LIBRARY_ELEMENT2] the [LibraryElement.publicNamespace] is set.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT3 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT3', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * 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 [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT4 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT4', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The partial [LibraryElement] associated with a library.
+ *
+ * [LIBRARY_ELEMENT4] plus resolved types for every element.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT5 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The flag specifying whether all analysis errors are computed in a specific
+ * library.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<bool> LIBRARY_ERRORS_READY =
+ new ResultDescriptor<bool>('LIBRARY_ERRORS_READY', false);
+
+/**
+ * The analysis errors associated with a compilation unit in a specific library.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> LIBRARY_UNIT_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'LIBRARY_UNIT_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * 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 [Source]s representing a compilation unit.
+ */
+final ListResultDescriptor<AnalysisError> PARSE_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'PARSE_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * The errors produced while resolving references outside of function bodies.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> PARTIALLY_RESOLVE_REFERENCES_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'PARTIALLY_RESOLVE_REFERENCES_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * The names (resolved and not) referenced by a unit.
+ *
+ * The result is only available for [Source]s representing a compilation unit.
+ */
+final ResultDescriptor<ReferencedNames> REFERENCED_NAMES =
+ new ResultDescriptor<ReferencedNames>('REFERENCED_NAMES', null);
+
+/**
+ * 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 [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> RESOLVE_REFERENCES_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'RESOLVE_REFERENCES_ERRORS', AnalysisError.NO_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 [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> RESOLVE_TYPE_NAMES_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'RESOLVE_TYPE_NAMES_ERRORS', AnalysisError.NO_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 [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT1 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT1', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The partially resolved [CompilationUnit] associated with a unit.
+ *
+ * All the enum member elements are built.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT2 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT2', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The partially resolved [CompilationUnit] associated with a unit.
+ *
+ * [RESOLVED_UNIT2] with resolved type names.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT3 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT3', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The partially resolved [CompilationUnit] associated with a unit.
+ *
+ * [RESOLVED_UNIT3] plus resolved local variables and formal parameters.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT4 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT4', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The resolved [CompilationUnit] associated with a compilation unit in which
+ * elements and types have been initially resolved outside of method bodies in
+ * addition to everything that is true of a [RESOLVED_UNIT4].
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT5 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT5', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The resolved [CompilationUnit] associated with a compilation unit in which
+ * the types of static variables have been inferred in addition to everything
+ * that is true of a [RESOLVED_UNIT5].
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT6 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT6', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The resolved [CompilationUnit] associated with a compilation unit in which
+ * the types of class members have been inferred in addition to everything that
+ * is true of a [RESOLVED_UNIT7].
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT7 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT7', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * The resolved [CompilationUnit] associated with a compilation unit, with
+ * constants not yet resolved.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT8 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT8', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
+ * 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 [Source]s representing a compilation unit.
+ */
+final ListResultDescriptor<AnalysisError> SCAN_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'SCAN_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * The [TypeProvider] of the [AnalysisContext].
+ */
+final ResultDescriptor<TypeProvider> TYPE_PROVIDER =
+ new ResultDescriptor<TypeProvider>('TYPE_PROVIDER', null);
+
+/**
+ * The [UsedImportedElements] of a [LibrarySpecificUnit].
+ */
+final ResultDescriptor<UsedImportedElements> USED_IMPORTED_ELEMENTS =
+ new ResultDescriptor<UsedImportedElements>('USED_IMPORTED_ELEMENTS', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The [UsedLocalElements] of a [LibrarySpecificUnit].
+ */
+final ResultDescriptor<UsedLocalElements> USED_LOCAL_ELEMENTS =
+ new ResultDescriptor<UsedLocalElements>('USED_LOCAL_ELEMENTS', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The errors produced while resolving variable references in a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> VARIABLE_REFERENCE_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'VARIABLE_REFERENCE_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * 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 [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> VERIFY_ERRORS =
+ new ListResultDescriptor<AnalysisError>(
+ 'VERIFY_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
+ * Return a list of errors containing the errors from the given [errors] list
+ * but with duplications removed.
+ */
+List<AnalysisError> removeDuplicateErrors(List<AnalysisError> errors) {
+ if (errors.isEmpty) {
+ return errors;
+ }
+ return errors.toSet().toList();
+}
+
+/**
+ * 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 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>[
+ COMPILATION_UNIT_CONSTANTS,
+ 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.
+ //
+ LibrarySpecificUnit librarySpecificUnit = target;
+ Source source = getRequiredSource();
+ CompilationUnit unit = getRequiredInput(PARSED_UNIT_INPUT_NAME);
+ //
+ // Build or reuse CompilationUnitElement.
+ //
+ unit = AstCloner.clone(unit);
+ AnalysisCache analysisCache =
+ (context as InternalAnalysisContext).analysisCache;
+ CompilationUnitElement element =
+ analysisCache.getValue(target, COMPILATION_UNIT_ELEMENT);
+ if (element == null) {
+ CompilationUnitBuilder builder = new CompilationUnitBuilder();
+ element = builder.buildCompilationUnit(
+ source, unit, librarySpecificUnit.library);
+ } else {
+ new DeclarationResolver().resolve(unit, element);
+ }
+ //
+ // Prepare constants.
+ //
+ ConstantFinder constantFinder =
+ new ConstantFinder(context, source, librarySpecificUnit.library);
+ unit.accept(constantFinder);
+ List<ConstantEvaluationTarget> constants = new List<
+ ConstantEvaluationTarget>.from(constantFinder.constantsToCompute);
+ //
+ // Record outputs.
+ //
+ outputs[COMPILATION_UNIT_CONSTANTS] = constants;
+ 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.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 whose value is the defining [LIBRARY_ELEMENT1].
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * 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.
+ //
+ LibraryElementImpl libraryElement = getRequiredInput(LIBRARY_INPUT);
+ 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);
+ 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) {
+ if (importedLibrary.isDartCore) {
+ explicitlyImportsCore = true;
+ }
+ 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(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(
+ 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ LIBRARY_INPUT: LIBRARY_ELEMENT1.of(source),
+ UNIT_INPUT_NAME:
+ RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, source)),
+ IMPORTS_LIBRARY_ELEMENT_INPUT_NAME:
+ IMPORTED_LIBRARIES.of(source).toMapOf(LIBRARY_ELEMENT1),
+ EXPORTS_LIBRARY_ELEMENT_INPUT_NAME:
+ EXPORTED_LIBRARIES.of(source).toMapOf(LIBRARY_ELEMENT1),
+ IMPORTS_SOURCE_KIND_INPUT_NAME:
+ IMPORTED_LIBRARIES.of(source).toMapOf(SOURCE_KIND),
+ EXPORTS_SOURCE_KIND_INPUT_NAME:
+ EXPORTED_LIBRARIES.of(source).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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
+ UNIT_INPUT: RESOLVED_UNIT1.of(unit)
+ };
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ LIBRARY_INPUT: LIBRARY_ELEMENT3.of(source),
+ 'exportsLibraryPublicNamespace':
+ EXPORT_SOURCE_CLOSURE.of(source).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 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,
+ 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;
+ hasPartDirective = true;
+ CompilationUnit partUnit = partUnitMap[partSource];
+ if (partUnit != null) {
+ 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.
+ //
+ if (context.exists(partSource)) {
+ String partLibraryName =
+ _getPartLibraryName(partSource, partUnit, directivesToResolve);
+ if (partLibraryName == null) {
+ errors.add(new AnalysisError(
+ 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(
+ 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(librarySource, 0, 0,
+ ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART)
+ ..setProperty(ErrorProperty.PARTS_LIBRARY_NAME, partsLibraryName);
+ } else {
+ error = new AnalysisError(librarySource, 0, 0,
+ ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART);
+ }
+ errors.add(error);
+ }
+ //
+ // Create and populate the library element.
+ //
+ AnalysisContext owningContext = context;
+ if (context is InternalAnalysisContext) {
+ InternalAnalysisContext internalContext = context;
+ owningContext = internalContext.getContextFor(librarySource);
+ }
+ LibraryElementImpl libraryElement =
+ new LibraryElementImpl.forNode(owningContext, libraryNameNode);
+ libraryElement.definingCompilationUnit = definingCompilationUnitElement;
+ libraryElement.entryPoint = entryPoint;
+ libraryElement.parts = sourcedCompilationUnits;
+ for (Directive directive in directivesToResolve) {
+ directive.element = libraryElement;
+ }
+ if (sourcedCompilationUnits.isNotEmpty) {
+ _patchTopLevelAccessors(libraryElement);
+ }
+ //
+ // Record outputs.
+ //
+ outputs[BUILD_LIBRARY_ERRORS] = errors;
+ 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 (PropertyAccessorElement 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 as PropertyAccessorElementImpl).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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ DEFINING_UNIT_INPUT:
+ RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, source)),
+ PARTS_UNIT_INPUT: INCLUDED_PARTS.of(source).toList((Source unit) {
+ return RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, unit));
+ })
+ };
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{LIBRARY_INPUT: LIBRARY_ELEMENT2.of(source)};
+ }
+
+ /**
+ * 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 [EXPORT_SOURCE_CLOSURE] of a library.
+ */
+class BuildSourceExportClosureTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the export closure.
+ */
+ static const String EXPORT_INPUT = 'EXPORT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'BuildSourceExportClosureTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[EXPORT_SOURCE_CLOSURE]);
+
+ BuildSourceExportClosureTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ List<Source> exportClosure = getRequiredInput(EXPORT_INPUT);
+ //
+ // Record output.
+ //
+ outputs[EXPORT_SOURCE_CLOSURE] = exportClosure;
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ EXPORT_INPUT: new _ExportSourceClosureTaskInput(source, LIBRARY_ELEMENT2)
+ };
+ }
+
+ /**
+ * Create a [BuildSourceExportClosureTask] based on the given [target] in
+ * the given [context].
+ */
+ static BuildSourceExportClosureTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new BuildSourceExportClosureTask(context, target);
+ }
+}
+
+/**
+ * A task that builds [IMPORT_EXPORT_SOURCE_CLOSURE] of a library, and also
+ * sets [IS_CLIENT].
+ */
+class BuildSourceImportExportClosureTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the import/export closure.
+ */
+ static const String IMPORT_EXPORT_INPUT = 'IMPORT_EXPORT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'BuildSourceImportExportClosureTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[IMPORT_EXPORT_SOURCE_CLOSURE, IS_CLIENT]);
+
+ BuildSourceImportExportClosureTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ List<Source> importExportClosure = getRequiredInput(IMPORT_EXPORT_INPUT);
+ Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML);
+ //
+ // Record outputs.
+ //
+ outputs[IMPORT_EXPORT_SOURCE_CLOSURE] = importExportClosure;
+ outputs[IS_CLIENT] = importExportClosure.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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ IMPORT_EXPORT_INPUT:
+ new _ImportExportSourceClosureTaskInput(source, LIBRARY_ELEMENT2)
+ };
+ }
+
+ /**
+ * Create a [BuildSourceImportExportClosureTask] based on the given [target]
+ * in the given [context].
+ */
+ static BuildSourceImportExportClosureTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new BuildSourceImportExportClosureTask(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 InternalAnalysisContext).typeProvider = typeProvider;
+ outputs[TYPE_PROVIDER] = typeProvider;
+ }
+
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ AnalysisContextTarget contextTarget = target;
+ SourceFactory sourceFactory = contextTarget.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, AnalysisTarget target) {
+ return new BuildTypeProviderTask(context, target);
+ }
+}
+
+/**
+ * A task that computes [CONSTANT_DEPENDENCIES] for a constant.
+ */
+class ComputeConstantDependenciesTask extends ConstantEvaluationAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT8] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ComputeConstantDependenciesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[CONSTANT_DEPENDENCIES]);
+
+ ComputeConstantDependenciesTask(
+ InternalAnalysisContext context, ConstantEvaluationTarget constant)
+ : super(context, constant);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ // Note: UNIT_INPUT is not needed. It is merely a bookkeeping dependency
+ // to ensure that resolution has occurred before we attempt to determine
+ // constant dependencies.
+ //
+ ConstantEvaluationTarget constant = target;
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Compute dependencies.
+ //
+ List<ConstantEvaluationTarget> dependencies = <ConstantEvaluationTarget>[];
+ new ConstantEvaluationEngine(typeProvider, context.declaredVariables)
+ .computeDependencies(constant, dependencies.add);
+ //
+ // Record outputs.
+ //
+ outputs[CONSTANT_DEPENDENCIES] = dependencies;
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ if (target is Element) {
+ CompilationUnitElementImpl unit = target
+ .getAncestor((Element element) => element is CompilationUnitElement);
+ return <String, TaskInput>{
+ UNIT_INPUT: RESOLVED_UNIT8
+ .of(new LibrarySpecificUnit(unit.librarySource, target.source)),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ } else if (target is ConstantEvaluationTarget_Annotation) {
+ return <String, TaskInput>{
+ UNIT_INPUT: RESOLVED_UNIT8
+ .of(new LibrarySpecificUnit(target.librarySource, target.source)),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+ throw new AnalysisException(
+ 'Cannot build inputs for a ${target.runtimeType}');
+ }
+
+ /**
+ * Create a [ComputeConstantDependenciesTask] based on the given [target] in
+ * the given [context].
+ */
+ static ComputeConstantDependenciesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ComputeConstantDependenciesTask(context, target);
+ }
+}
+
+/**
+ * A task that computes the value of a constant ([CONSTANT_VALUE]) and
+ * stores it in the element model.
+ */
+class ComputeConstantValueTask extends ConstantEvaluationAnalysisTask {
+ /**
+ * The name of the input which ensures that dependent constants are evaluated
+ * before the target.
+ */
+ static const String DEPENDENCIES_INPUT = 'DEPENDENCIES_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ComputeConstantValueTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[CONSTANT_VALUE]);
+
+ ComputeConstantValueTask(
+ InternalAnalysisContext context, ConstantEvaluationTarget constant)
+ : super(context, constant);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ bool get handlesDependencyCycles => true;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ // Note: DEPENDENCIES_INPUT is not needed. It is merely a bookkeeping
+ // dependency to ensure that the constants that this constant depends on
+ // are computed first.
+ ConstantEvaluationTarget constant = target;
+ AnalysisContext context = constant.context;
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Compute the value of the constant, or report an error if there was a
+ // cycle.
+ //
+ ConstantEvaluationEngine constantEvaluationEngine =
+ new ConstantEvaluationEngine(typeProvider, context.declaredVariables);
+ if (dependencyCycle == null) {
+ constantEvaluationEngine.computeConstantValue(constant);
+ } else {
+ List<ConstantEvaluationTarget> constantsInCycle =
+ <ConstantEvaluationTarget>[];
+ for (WorkItem workItem in dependencyCycle) {
+ if (workItem.descriptor == DESCRIPTOR) {
+ constantsInCycle.add(workItem.target);
+ }
+ }
+ assert(constantsInCycle.isNotEmpty);
+ constantEvaluationEngine.generateCycleError(constantsInCycle, constant);
+ }
+ //
+ // Record outputs.
+ //
+ outputs[CONSTANT_VALUE] = constant;
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ ConstantEvaluationTarget evaluationTarget = target;
+ return <String, TaskInput>{
+ DEPENDENCIES_INPUT:
+ CONSTANT_DEPENDENCIES.of(evaluationTarget).toListOf(CONSTANT_VALUE),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * Create a [ComputeConstantValueTask] based on the given [target] in the
+ * given [context].
+ */
+ static ComputeConstantValueTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ComputeConstantValueTask(context, target);
+ }
+}
+
+/**
+ * A task that computes the [INFERABLE_STATIC_VARIABLE_DEPENDENCIES] for a
+ * static variable whose type should be inferred.
+ */
+class ComputeInferableStaticVariableDependenciesTask
+ extends ConstantEvaluationAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT5] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ComputeInferableStaticVariableDependenciesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[INFERABLE_STATIC_VARIABLE_DEPENDENCIES]);
+
+ ComputeInferableStaticVariableDependenciesTask(
+ InternalAnalysisContext context, VariableElement variable)
+ : super(context, variable);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ VariableElement variable = target;
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ //
+ // Compute dependencies.
+ //
+ NodeLocator locator = new NodeLocator(variable.nameOffset);
+ AstNode node = locator.searchWithin(unit);
+ VariableDeclaration declaration =
+ node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
+ if (declaration == null || declaration.name != node) {
+ throw new AnalysisException(
+ "NodeLocator failed to find a variable's declaration");
+ }
+ VariableGatherer gatherer = new VariableGatherer(_isInferableStatic);
+ declaration.initializer.accept(gatherer);
+ //
+ // Record outputs.
+ //
+ outputs[INFERABLE_STATIC_VARIABLE_DEPENDENCIES] = gatherer.results.toList();
+ }
+
+ /**
+ * Return `true` if the given [variable] is a static variable whose type
+ * should be inferred.
+ */
+ bool _isInferableStatic(VariableElement variable) => variable.isStatic &&
+ variable.hasImplicitType &&
+ variable.initializer != null;
+
+ /**
+ * 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(AnalysisTarget target) {
+ if (target is VariableElement) {
+ CompilationUnitElementImpl unit = target
+ .getAncestor((Element element) => element is CompilationUnitElement);
+ return <String, TaskInput>{
+ UNIT_INPUT: RESOLVED_UNIT5
+ .of(new LibrarySpecificUnit(unit.librarySource, unit.source))
+ };
+ }
+ throw new AnalysisException(
+ 'Cannot build inputs for a ${target.runtimeType}');
+ }
+
+ /**
+ * Create a [ComputeInferableStaticVariableDependenciesTask] based on the
+ * given [target] in the given [context].
+ */
+ static ComputeInferableStaticVariableDependenciesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ComputeInferableStaticVariableDependenciesTask(context, target);
+ }
+}
+
+/**
+ * A base class for analysis tasks whose target is expected to be a
+ * [ConstantEvaluationTarget].
+ */
+abstract class ConstantEvaluationAnalysisTask extends AnalysisTask {
+ /**
+ * Initialize a newly created task to perform analysis within the given
+ * [context] in order to produce results for the given [constant].
+ */
+ ConstantEvaluationAnalysisTask(
+ AnalysisContext context, ConstantEvaluationTarget constant)
+ : super(context, constant);
+
+ @override
+ String get description {
+ Source source = target.source;
+ String sourceName = source == null ? '<unknown source>' : source.fullName;
+ return '${descriptor.name} for element $target in source $sourceName';
+ }
+}
+
+/**
+ * Interface for [AnalysisTarget]s for which constant evaluation can be
+ * performed.
+ */
+abstract class ConstantEvaluationTarget extends AnalysisTarget {
+ /**
+ * Return the [AnalysisContext] which should be used to evaluate this
+ * constant.
+ */
+ AnalysisContext get context;
+}
+
+/**
+ * A task that computes a list of the libraries containing the target source.
+ */
+class ContainingLibrariesTask extends SourceBasedAnalysisTask {
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ContainingLibrariesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[CONTAINING_LIBRARIES]);
+
+ ContainingLibrariesTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ // TODO(brianwilkerson) This value can change as new libraries are analyzed
+ // so we need some way of making sure that this result is removed from the
+ // cache appropriately.
+ Source source = getRequiredSource();
+ outputs[CONTAINING_LIBRARIES] = context.getLibrariesContaining(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 [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ return <String, TaskInput>{};
+ }
+
+ /**
+ * Create a [ContainingLibrariesTask] based on the given [target] in the given
+ * [context].
+ */
+ static ContainingLibrariesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ContainingLibrariesTask(context, target);
+ }
+}
+
+/**
+ * The description for a change in a Dart source.
+ */
+class DartDelta extends Delta {
+ bool hasDirectiveChange = false;
+
+ final Set<String> addedNames = new Set<String>();
+ final Set<String> changedNames = new Set<String>();
+ final Set<String> removedNames = new Set<String>();
+
+ final Set<Source> invalidatedSources = new Set<Source>();
+
+ DartDelta(Source source) : super(source) {
+ invalidatedSources.add(source);
+ }
+
+ void elementAdded(Element element) {
+ addedNames.add(element.name);
+ }
+
+ void elementChanged(Element element) {
+ changedNames.add(element.name);
+ }
+
+ void elementRemoved(Element element) {
+ removedNames.add(element.name);
+ }
+
+ bool isNameAffected(String name) {
+ return addedNames.contains(name) ||
+ changedNames.contains(name) ||
+ removedNames.contains(name);
+ }
+
+ bool nameChanged(String name) {
+ return changedNames.add(name);
+ }
+
+ @override
+ DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
+ ResultDescriptor descriptor) {
+ if (hasDirectiveChange) {
+ return DeltaResult.INVALIDATE;
+ }
+ // Prepare target source.
+ Source targetSource = null;
+ if (target is Source) {
+ targetSource = target;
+ }
+ if (target is LibrarySpecificUnit) {
+ targetSource = target.library;
+ }
+ if (target is Element) {
+ targetSource = target.source;
+ }
+ // Keep results that are updated incrementally.
+ // If we want to analyze only some references to the source being changed,
+ // we need to keep the same instances of CompilationUnitElement and
+ // LibraryElement.
+ if (targetSource == source) {
+ if (ParseDartTask.DESCRIPTOR.results.contains(descriptor)) {
+ return DeltaResult.KEEP_CONTINUE;
+ }
+ if (BuildCompilationUnitElementTask.DESCRIPTOR.results
+ .contains(descriptor)) {
+ return DeltaResult.KEEP_CONTINUE;
+ }
+ if (BuildLibraryElementTask.DESCRIPTOR.results.contains(descriptor)) {
+ return DeltaResult.KEEP_CONTINUE;
+ }
+ return DeltaResult.INVALIDATE;
+ }
+ // Use the target library dependency information to decide whether
+ // the delta affects the library.
+ if (targetSource != null) {
+ List<Source> librarySources =
+ context.getLibrariesContaining(targetSource);
+ for (Source librarySource in librarySources) {
+ AnalysisCache cache = context.analysisCache;
+ ReferencedNames referencedNames =
+ cache.getValue(librarySource, REFERENCED_NAMES);
+ if (referencedNames == null) {
+ return DeltaResult.INVALIDATE;
+ }
+ referencedNames.addChangedElements(this);
+ if (referencedNames.isAffectedBy(this)) {
+ return DeltaResult.INVALIDATE;
+ }
+ }
+ return DeltaResult.STOP;
+ }
+ // We don't know what to do with the given target, invalidate it.
+ return DeltaResult.INVALIDATE;
+ }
+}
+
+/**
+ * A task that merges all of the errors for a single source into a single list
+ * of errors.
+ */
+class DartErrorsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [BUILD_DIRECTIVES_ERRORS] input.
+ */
+ static const String BUILD_DIRECTIVES_ERRORS_INPUT = 'BUILD_DIRECTIVES_ERRORS';
+
+ /**
+ * The name of the [BUILD_LIBRARY_ERRORS] input.
+ */
+ static const String BUILD_LIBRARY_ERRORS_INPUT = 'BUILD_LIBRARY_ERRORS';
+
+ /**
+ * The name of the [LIBRARY_UNIT_ERRORS] input.
+ */
+ static const String LIBRARY_UNIT_ERRORS_INPUT = 'LIBRARY_UNIT_ERRORS';
+
+ /**
+ * The name of the [PARSE_ERRORS] input.
+ */
+ static const String PARSE_ERRORS_INPUT = 'PARSE_ERRORS';
+
+ /**
+ * The name of the [SCAN_ERRORS] input.
+ */
+ static const String SCAN_ERRORS_INPUT = 'SCAN_ERRORS';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartErrorsTask',
+ createTask, buildInputs, <ResultDescriptor>[DART_ERRORS]);
+
+ DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
+ errorLists.add(getRequiredInput(BUILD_DIRECTIVES_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(BUILD_LIBRARY_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(PARSE_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(SCAN_ERRORS_INPUT));
+ Map<Source, List<AnalysisError>> unitErrors =
+ getRequiredInput(LIBRARY_UNIT_ERRORS_INPUT);
+ for (List<AnalysisError> errors in unitErrors.values) {
+ errorLists.add(errors);
+ }
+ //
+ // Record outputs.
+ //
+ outputs[DART_ERRORS] = AnalysisError.mergeLists(errorLists);
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ BUILD_DIRECTIVES_ERRORS_INPUT: BUILD_DIRECTIVES_ERRORS.of(source),
+ BUILD_LIBRARY_ERRORS_INPUT: BUILD_LIBRARY_ERRORS.of(source),
+ PARSE_ERRORS_INPUT: PARSE_ERRORS.of(source),
+ SCAN_ERRORS_INPUT: SCAN_ERRORS.of(source),
+ LIBRARY_UNIT_ERRORS_INPUT:
+ CONTAINING_LIBRARIES.of(source).toMap((Source library) {
+ LibrarySpecificUnit unit = new LibrarySpecificUnit(library, source);
+ return LIBRARY_UNIT_ERRORS.of(unit);
+ })
+ };
+ }
+
+ /**
+ * Create a [DartErrorsTask] based on the given [target] in the given
+ * [context].
+ */
+ static DartErrorsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new DartErrorsTask(context, target);
+ }
+}
+
+/**
+ * A task that builds [RESOLVED_UNIT] for a unit.
+ */
+class EvaluateUnitConstantsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT8] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the [CONSTANT_VALUE] input.
+ */
+ static const String CONSTANT_VALUES = 'CONSTANT_VALUES';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'EvaluateUnitConstantsTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[RESOLVED_UNIT]);
+
+ EvaluateUnitConstantsTask(AnalysisContext context, LibrarySpecificUnit target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ // No actual work needs to be performed; the task manager will ensure that
+ // all constants are evaluated before this method is called.
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ 'libraryElement': LIBRARY_ELEMENT.of(unit.library),
+ UNIT_INPUT: RESOLVED_UNIT8.of(unit),
+ CONSTANT_VALUES:
+ COMPILATION_UNIT_CONSTANTS.of(unit).toListOf(CONSTANT_VALUE)
+ };
+ }
+
+ /**
+ * Create an [EvaluateUnitConstantsTask] based on the given [target] in
+ * the given [context].
+ */
+ static EvaluateUnitConstantsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new EvaluateUnitConstantsTask(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_UNIT8] 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT8.of(unit)};
+ }
+
+ /**
+ * Create a [GatherUsedImportedElementsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GatherUsedImportedElementsTask createTask(
+ AnalysisContext context, AnalysisTarget 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_UNIT8] 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT8.of(unit)};
+ }
+
+ /**
+ * Create a [GatherUsedLocalElementsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GatherUsedLocalElementsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new GatherUsedLocalElementsTask(context, target);
+ }
+}
+
+/**
+ * A task that generates [HINTS] for a unit.
+ */
+class GenerateHintsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT8] input.
+ */
+ static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
+
+ /**
+ * 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 name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * 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() {
+ AnalysisOptions analysisOptions = context.analysisOptions;
+ if (!analysisOptions.hint) {
+ outputs[HINTS] = AnalysisError.NO_ERRORS;
+ return;
+ }
+ //
+ // Prepare collectors.
+ //
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ Source source = getRequiredSource();
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(RESOLVED_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 (analysisOptions.dart2jsHint) {
+ unit.accept(new Dart2JSVerifier(errorReporter));
+ }
+ // Dart best practices.
+ InheritanceManager inheritanceManager =
+ new InheritanceManager(libraryElement);
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ Source libSource = unit.library;
+ return <String, TaskInput>{
+ RESOLVED_UNIT_INPUT: RESOLVED_UNIT.of(unit),
+ USED_LOCAL_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) {
+ LibrarySpecificUnit target = new LibrarySpecificUnit(libSource, unit);
+ return USED_LOCAL_ELEMENTS.of(target);
+ }),
+ USED_IMPORTED_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) {
+ LibrarySpecificUnit target = new LibrarySpecificUnit(libSource, unit);
+ return USED_IMPORTED_ELEMENTS.of(target);
+ }),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * Create a [GenerateHintsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GenerateHintsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new GenerateHintsTask(context, target);
+ }
+}
+
+/**
+ * An abstract class that defines utility methods that are useful for tasks
+ * operating on static variables.
+ */
+abstract class InferStaticVariableTask extends ConstantEvaluationAnalysisTask {
+ InferStaticVariableTask(
+ InternalAnalysisContext context, VariableElement variable)
+ : super(context, variable);
+
+ /**
+ * Return the declaration of the target within the given compilation [unit].
+ * Throw an exception if the declaration cannot be found.
+ */
+ VariableDeclaration getDeclaration(CompilationUnit unit) {
+ VariableElement variable = target;
+ NodeLocator locator = new NodeLocator(variable.nameOffset);
+ AstNode node = locator.searchWithin(unit);
+ VariableDeclaration declaration =
+ node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
+ if (declaration == null || declaration.name != node) {
+ throw new AnalysisException(
+ "Failed to find the declaration of the variable ${variable.displayName} in ${variable.source}");
+ }
+ return declaration;
+ }
+}
+
+/**
+ * A task that ensures that all of the inferrable static variables in a
+ * compilation unit have had their type inferred.
+ */
+class InferStaticVariableTypesInUnitTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the input whose value is the [RESOLVED_UNIT5] for the
+ * compilation unit.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the input whose value is a list of the inferrable static
+ * variables whose types have been computed.
+ */
+ static const String INFERRED_VARIABLES_INPUT = 'INFERRED_VARIABLES_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'InferStaticVariableTypesInUnitTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[RESOLVED_UNIT6]);
+
+ /**
+ * Initialize a newly created task to build a library element for the given
+ * [unit] in the given [context].
+ */
+ InferStaticVariableTypesInUnitTask(
+ InternalAnalysisContext context, LibrarySpecificUnit unit)
+ : super(context, unit);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ //
+ // Record outputs. There is no additional work to be done at this time
+ // because the work has implicitly been done by virtue of the task model
+ // preparing all of the inputs.
+ //
+ outputs[RESOLVED_UNIT6] = 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
+ * [libSource].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ INFERRED_VARIABLES_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT
+ .of(unit)
+ .toListOf(INFERRED_STATIC_VARIABLE),
+ UNIT_INPUT: RESOLVED_UNIT5.of(unit)
+ };
+ }
+
+ /**
+ * Create a [InferStaticVariableTypesInUnitTask] based on the given [target] in the
+ * given [context].
+ */
+ static InferStaticVariableTypesInUnitTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new InferStaticVariableTypesInUnitTask(context, target);
+ }
+}
+
+/**
+ * A task that computes the type of an inferrable static variable and
+ * stores it in the element model.
+ */
+class InferStaticVariableTypeTask extends InferStaticVariableTask {
+ /**
+ * The name of the input which ensures that dependent values have their type
+ * inferred before the target.
+ */
+ static const String DEPENDENCIES_INPUT = 'DEPENDENCIES_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT5] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'InferStaticVariableTypeTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[INFERRED_STATIC_VARIABLE]);
+
+ InferStaticVariableTypeTask(
+ InternalAnalysisContext context, VariableElement variable)
+ : super(context, variable);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ bool get handlesDependencyCycles => true;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ // Note: DEPENDENCIES_INPUT is not needed. It is merely a bookkeeping
+ // dependency to ensure that the variables that this variable references
+ // have types inferred before inferring the type of this variable.
+ //
+ VariableElementImpl variable = target;
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Re-resolve the variable's initializer so that the inferred types of other
+ // variables will be propagated.
+ //
+ NodeLocator locator = new NodeLocator(variable.nameOffset);
+ AstNode node = locator.searchWithin(unit);
+ VariableDeclaration declaration =
+ node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
+ if (declaration == null || declaration.name != node) {
+ throw new AnalysisException(
+ "NodeLocator failed to find a variable's declaration");
+ }
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ Expression initializer = declaration.initializer;
+ ResolutionContext resolutionContext =
+ ResolutionContextBuilder.contextFor(initializer, errorListener);
+ ResolverVisitor visitor = new ResolverVisitor(
+ variable.library, variable.source, typeProvider, errorListener,
+ nameScope: resolutionContext.scope);
+ if (resolutionContext.enclosingClassDeclaration != null) {
+ visitor.prepareToResolveMembersInClass(
+ resolutionContext.enclosingClassDeclaration);
+ }
+ visitor.initForIncrementalResolution();
+ initializer.accept(visitor);
+ //
+ // Record the type of the variable.
+ //
+ DartType newType = initializer.staticType;
+ variable.type = newType;
+ (variable.initializer as ExecutableElementImpl).returnType = newType;
+ if (variable is PropertyInducingElementImpl) {
+ setReturnType(variable.getter, newType);
+ setParameterType(variable.setter, newType);
+ }
+ //
+ // Record outputs.
+ //
+ outputs[INFERRED_STATIC_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
+ * [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ VariableElement variable = target;
+ LibrarySpecificUnit unit =
+ new LibrarySpecificUnit(variable.library.source, variable.source);
+ return <String, TaskInput>{
+ DEPENDENCIES_INPUT: INFERABLE_STATIC_VARIABLE_DEPENDENCIES
+ .of(variable)
+ .toListOf(INFERRED_STATIC_VARIABLE),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
+ UNIT_INPUT: RESOLVED_UNIT5.of(unit)
+ };
+ }
+
+ /**
+ * Create a [InferStaticVariableTypeTask] based on the given [target] in the
+ * given [context].
+ */
+ static InferStaticVariableTypeTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new InferStaticVariableTypeTask(context, target);
+ }
+}
+
+/**
+ * A task computes all of the errors of all of the units for a single
+ * library source and sets the [LIBRARY_ERRORS_READY] flag.
+ */
+class LibraryErrorsReadyTask extends SourceBasedAnalysisTask {
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'LibraryErrorsReadyTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[LIBRARY_ERRORS_READY]);
+
+ LibraryErrorsReadyTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ outputs[LIBRARY_ERRORS_READY] = true;
+ }
+
+ /**
+ * 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].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ 'allErrors': UNITS.of(source).toListOf(DART_ERRORS)
+ };
+ }
+
+ /**
+ * Create a [LibraryErrorsReadyTask] based on the given [target] in the given
+ * [context].
+ */
+ static LibraryErrorsReadyTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new LibraryErrorsReadyTask(context, target);
+ }
+}
+
+/**
+ * A task that merges all of the errors for a single source into a single list
+ * of errors.
+ */
+class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [HINTS] input.
+ */
+ static const String HINTS_INPUT = 'HINTS';
+
+ /**
+ * The name of the [RESOLVE_REFERENCES_ERRORS] input.
+ */
+ static const String RESOLVE_REFERENCES_ERRORS_INPUT =
+ 'RESOLVE_REFERENCES_ERRORS';
+
+ /**
+ * The name of the [RESOLVE_TYPE_NAMES_ERRORS] input.
+ */
+ static const String RESOLVE_TYPE_NAMES_ERRORS_INPUT =
+ 'RESOLVE_TYPE_NAMES_ERRORS';
+
+ /**
+ * The name of the [VARIABLE_REFERENCE_ERRORS] input.
+ */
+ static const String VARIABLE_REFERENCE_ERRORS_INPUT =
+ 'VARIABLE_REFERENCE_ERRORS';
+
+ /**
+ * The name of the [VERIFY_ERRORS] input.
+ */
+ static const String VERIFY_ERRORS_INPUT = 'VERIFY_ERRORS';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'LibraryUnitErrorsTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[LIBRARY_UNIT_ERRORS]);
+
+ LibraryUnitErrorsTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
+ errorLists.add(getRequiredInput(HINTS_INPUT));
+ errorLists.add(getRequiredInput(RESOLVE_REFERENCES_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(VARIABLE_REFERENCE_ERRORS_INPUT));
+ errorLists.add(getRequiredInput(VERIFY_ERRORS_INPUT));
+ //
+ // Record outputs.
+ //
+ outputs[LIBRARY_UNIT_ERRORS] = AnalysisError.mergeLists(errorLists);
+ }
+
+ /**
+ * 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 [unit].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ HINTS_INPUT: HINTS.of(unit),
+ RESOLVE_REFERENCES_ERRORS_INPUT: RESOLVE_REFERENCES_ERRORS.of(unit),
+ RESOLVE_TYPE_NAMES_ERRORS_INPUT: RESOLVE_TYPE_NAMES_ERRORS.of(unit),
+ VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit),
+ VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit)
+ };
+ }
+
+ /**
+ * Create a [LibraryUnitErrorsTask] based on the given [target] in the given
+ * [context].
+ */
+ static LibraryUnitErrorsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new LibraryUnitErrorsTask(context, target);
+ }
+}
+
+/**
+ * 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 modification time of the file.
+ */
+ static const String MODIFICATION_TIME_INPUT_NAME =
+ 'MODIFICATION_TIME_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>[
+ EXPLICITLY_IMPORTED_LIBRARIES,
+ 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);
+ int modificationTime = getRequiredInput(MODIFICATION_TIME_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);
+ parser.parseGenericMethods = options.enableGenericMethods;
+ CompilationUnit unit = parser.parseCompilationUnit(tokenStream);
+ unit.lineInfo = lineInfo;
+
+ bool hasNonPartOfDirective = false;
+ bool hasPartOfDirective = false;
+ HashSet<Source> explicitlyImportedSourceSet = new HashSet<Source>();
+ HashSet<Source> exportedSourceSet = new HashSet<Source>();
+ HashSet<Source> includedSourceSet = 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) {
+ exportedSourceSet.add(referencedSource);
+ } else if (directive is ImportDirective) {
+ explicitlyImportedSourceSet.add(referencedSource);
+ } else if (directive is PartDirective) {
+ includedSourceSet.add(referencedSource);
+ } else {
+ throw new AnalysisException(
+ '$runtimeType failed to handle a ${directive.runtimeType}');
+ }
+ }
+ }
+ }
+ }
+ //
+ // Always include "dart:core" source.
+ //
+ HashSet<Source> importedSourceSet =
+ new HashSet.from(explicitlyImportedSourceSet);
+ Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE);
+ importedSourceSet.add(coreLibrarySource);
+ //
+ // Compute kind.
+ //
+ SourceKind sourceKind = SourceKind.LIBRARY;
+ if (modificationTime == -1) {
+ sourceKind = SourceKind.UNKNOWN;
+ } else if (hasPartOfDirective && !hasNonPartOfDirective) {
+ sourceKind = SourceKind.PART;
+ }
+ //
+ // Record outputs.
+ //
+ List<Source> explicitlyImportedSources =
+ explicitlyImportedSourceSet.toList();
+ List<Source> exportedSources = exportedSourceSet.toList();
+ List<Source> importedSources = importedSourceSet.toList();
+ List<Source> includedSources = includedSourceSet.toList();
+ List<AnalysisError> parseErrors =
+ removeDuplicateErrors(errorListener.errors);
+ List<Source> unitSources = <Source>[source]..addAll(includedSourceSet);
+ outputs[EXPLICITLY_IMPORTED_LIBRARIES] = explicitlyImportedSources;
+ outputs[EXPORTED_LIBRARIES] = exportedSources;
+ outputs[IMPORTED_LIBRARIES] = importedSources;
+ outputs[INCLUDED_PARTS] = includedSources;
+ outputs[PARSE_ERRORS] = parseErrors;
+ outputs[PARSED_UNIT] = unit;
+ outputs[SOURCE_KIND] = sourceKind;
+ outputs[UNITS] = unitSources;
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ return <String, TaskInput>{
+ LINE_INFO_INPUT_NAME: LINE_INFO.of(target),
+ MODIFICATION_TIME_INPUT_NAME: MODIFICATION_TIME.of(target),
+ TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(target)
+ };
+ }
+
+ /**
+ * 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(librarySource, uriLiteral.offset,
+ uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION));
+ return null;
+ }
+ if (code == UriValidationCode.INVALID_URI) {
+ errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
+ uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent]));
+ return null;
+ }
+ throw new AnalysisException('Failed to handle validation code: $code');
+ }
+}
+
+/**
+ * A task that builds [RESOLVED_UNIT5] for a unit.
+ */
+class PartiallyResolveUnitReferencesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT5] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT4] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'PartiallyResolveUnitReferencesTask',
+ createTask,
+ buildInputs, <ResultDescriptor>[
+ CLASSES_IN_UNIT,
+ INFERABLE_STATIC_VARIABLES_IN_UNIT,
+ PARTIALLY_RESOLVE_REFERENCES_ERRORS,
+ RESOLVED_UNIT5
+ ]);
+
+ PartiallyResolveUnitReferencesTask(
+ 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 = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Resolve references.
+ //
+ InheritanceManager inheritanceManager =
+ new InheritanceManager(libraryElement);
+ // TODO(brianwilkerson) Improve performance by not resolving anything inside
+ // function bodies. Function bodies will be resolved later so this is wasted
+ // effort.
+ AstVisitor visitor = new ResolverVisitor(
+ libraryElement, unitElement.source, typeProvider, errorListener,
+ inheritanceManager: inheritanceManager);
+ unit.accept(visitor);
+ //
+ // Prepare targets for inference.
+ //
+ List<VariableElement> staticVariables = <VariableElement>[];
+ List<ClassElement> classes = <ClassElement>[];
+ if (context.analysisOptions.strongMode) {
+ InferrenceFinder inferrenceFinder = new InferrenceFinder();
+ unit.accept(inferrenceFinder);
+ staticVariables = inferrenceFinder.staticVariables;
+ classes = inferrenceFinder.classes;
+ }
+ //
+ // Record outputs.
+ //
+ outputs[CLASSES_IN_UNIT] = classes;
+ outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = staticVariables;
+ outputs[PARTIALLY_RESOLVE_REFERENCES_ERRORS] =
+ removeDuplicateErrors(errorListener.errors);
+ 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ 'fullyBuiltLibraryElements': IMPORT_EXPORT_SOURCE_CLOSURE
+ .of(unit.library)
+ .toListOf(LIBRARY_ELEMENT5),
+ LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
+ UNIT_INPUT: RESOLVED_UNIT4.of(unit),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * Create a [PartiallyResolveUnitReferencesTask] based on the given [target]
+ * in the given [context].
+ */
+ static PartiallyResolveUnitReferencesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new PartiallyResolveUnitReferencesTask(context, target);
+ }
+}
+
+/**
+ * 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);
+ }
+}
+
+/**
+ * Information about a library - which names it uses, which names it defines
+ * with their externally visible dependencies.
+ */
+class ReferencedNames {
+ final Set<String> names = new Set<String>();
+ final Map<String, Set<String>> userToDependsOn = <String, Set<String>>{};
+
+ /**
+ * Updates [delta] by adding names that are changed in this library.
+ */
+ void addChangedElements(DartDelta delta) {
+ bool hasProgress = true;
+ while (hasProgress) {
+ hasProgress = false;
+ userToDependsOn.forEach((user, dependencies) {
+ for (String dependency in dependencies) {
+ if (delta.isNameAffected(dependency)) {
+ if (delta.nameChanged(user)) {
+ hasProgress = true;
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns `true` if the library described by this object is affected by
+ * the given [delta].
+ */
+ bool isAffectedBy(DartDelta delta) {
+ for (String name in names) {
+ if (delta.isNameAffected(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * A builder for creating [ReferencedNames].
+ *
+ * TODO(scheglov) Record dependencies for all other top-level declarations.
+ */
+class ReferencedNamesBuilder extends RecursiveAstVisitor {
+ final ReferencedNames names;
+ int bodyLevel = 0;
+ Set<String> dependsOn;
+
+ ReferencedNamesBuilder(this.names);
+
+ ReferencedNames build(CompilationUnit unit) {
+ unit.accept(this);
+ return names;
+ }
+
+ @override
+ visitBlockFunctionBody(BlockFunctionBody node) {
+ try {
+ bodyLevel++;
+ super.visitBlockFunctionBody(node);
+ } finally {
+ bodyLevel--;
+ }
+ }
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ dependsOn = new Set<String>();
+ super.visitClassDeclaration(node);
+ names.userToDependsOn[node.name.name] = dependsOn;
+ dependsOn = null;
+ }
+
+ @override
+ visitExpressionFunctionBody(ExpressionFunctionBody node) {
+ try {
+ bodyLevel++;
+ super.visitExpressionFunctionBody(node);
+ } finally {
+ bodyLevel--;
+ }
+ }
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ if (!node.inDeclarationContext()) {
+ String name = node.name;
+ names.names.add(name);
+ if (dependsOn != null && bodyLevel == 0) {
+ dependsOn.add(name);
+ }
+ }
+ }
+}
+
+/**
+ * A task that finishes resolution by requesting [RESOLVED_UNIT_NO_CONSTANTS] for every
+ * unit in the libraries closure and produces [LIBRARY_ELEMENT].
+ */
+class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT5] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the list of [RESOLVED_UNIT8] input.
+ */
+ static const String UNITS_INPUT = 'UNITS_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ResolveLibraryReferencesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[LIBRARY_ELEMENT, REFERENCED_NAMES]);
+
+ ResolveLibraryReferencesTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+ List<CompilationUnit> units = getRequiredInput(UNITS_INPUT);
+ // Compute referenced names.
+ ReferencedNames referencedNames = new ReferencedNames();
+ for (CompilationUnit unit in units) {
+ new ReferencedNamesBuilder(referencedNames).build(unit);
+ }
+ //
+ // Record outputs.
+ //
+ outputs[LIBRARY_ELEMENT] = library;
+ outputs[REFERENCED_NAMES] = referencedNames;
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
+ UNITS_INPUT: UNITS.of(source).toList((Source unit) =>
+ RESOLVED_UNIT8.of(new LibrarySpecificUnit(source, unit))),
+ 'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE
+ .of(source)
+ .toMapOf(UNITS)
+ .toFlattenList((Source library, Source unit) =>
+ RESOLVED_UNIT8.of(new LibrarySpecificUnit(library, unit))),
+ };
+ }
+
+ /**
+ * Create a [ResolveLibraryReferencesTask] based on the given [target] in
+ * the given [context].
+ */
+ static ResolveLibraryReferencesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ResolveLibraryReferencesTask(context, target);
+ }
+}
+
+/**
+ * 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(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ 'resolvedUnit': UNITS.of(source).toList((Source unit) =>
+ RESOLVED_UNIT3.of(new LibrarySpecificUnit(source, unit))),
+ LIBRARY_INPUT: LIBRARY_ELEMENT4.of(source)
+ };
+ }
+
+ /**
+ * 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_UNIT8] for a unit.
+ */
+class ResolveUnitReferencesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT5] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT4] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ResolveUnitReferencesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[RESOLVE_REFERENCES_ERRORS, RESOLVED_UNIT8]);
+
+ ResolveUnitReferencesTask(
+ 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 = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Resolve references.
+ //
+ InheritanceManager inheritanceManager =
+ new InheritanceManager(libraryElement);
+ AstVisitor visitor = new ResolverVisitor(
+ libraryElement, unitElement.source, typeProvider, errorListener,
+ inheritanceManager: inheritanceManager);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[RESOLVE_REFERENCES_ERRORS] =
+ removeDuplicateErrors(errorListener.errors);
+ outputs[RESOLVED_UNIT8] = 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ 'fullyBuiltLibraryElements': IMPORT_EXPORT_SOURCE_CLOSURE
+ .of(unit.library)
+ .toListOf(LIBRARY_ELEMENT5),
+ LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
+ UNIT_INPUT: RESOLVED_UNIT4.of(unit),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * Create a [ResolveUnitReferencesTask] based on the given [target] in
+ * the given [context].
+ */
+ static ResolveUnitReferencesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ResolveUnitReferencesTask(context, target);
+ }
+}
+
+/**
+ * A task that builds [RESOLVED_UNIT3] for a unit.
+ */
+class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the input whose value is the defining [LIBRARY_ELEMENT4].
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT2] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ResolveUnitTypeNamesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[RESOLVE_TYPE_NAMES_ERRORS, RESOLVED_UNIT3]);
+
+ ResolveUnitTypeNamesTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ //
+ // Prepare inputs.
+ //
+ LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ //
+ // Resolve TypeName nodes.
+ //
+ TypeResolverVisitor visitor = new TypeResolverVisitor(
+ library, unitElement.source, typeProvider, errorListener);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[RESOLVE_TYPE_NAMES_ERRORS] =
+ removeDuplicateErrors(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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ 'importsExportNamespace':
+ IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4),
+ LIBRARY_INPUT: LIBRARY_ELEMENT4.of(unit.library),
+ UNIT_INPUT: RESOLVED_UNIT2.of(unit),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * 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_UNIT4] for a unit.
+ */
+class ResolveVariableReferencesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT1] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT3] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ResolveVariableReferencesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[RESOLVED_UNIT4, VARIABLE_REFERENCE_ERRORS]);
+
+ 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 = getRequiredInput(TYPE_PROVIDER_INPUT);
+ Scope nameScope = new LibraryScope(libraryElement, errorListener);
+ AstVisitor visitor = new VariableResolverVisitor(
+ libraryElement, unitElement.source, typeProvider, errorListener,
+ nameScope: nameScope);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[RESOLVED_UNIT4] = unit;
+ outputs[VARIABLE_REFERENCE_ERRORS] =
+ removeDuplicateErrors(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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ LIBRARY_INPUT: LIBRARY_ELEMENT1.of(unit.library),
+ UNIT_INPUT: RESOLVED_UNIT1.of(unit),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * 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();
+
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ if (context.getModificationStamp(target.source) < 0) {
+ String message = 'Content could not be read';
+ if (context is InternalAnalysisContext) {
+ CacheEntry entry =
+ (context as InternalAnalysisContext).getCacheEntry(target);
+ CaughtException exception = entry.exception;
+ if (exception != null) {
+ message = exception.toString();
+ }
+ }
+ errorListener.onError(new AnalysisError(
+ source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+ }
+ if (target is DartScript) {
+ DartScript script = target;
+ List<ScriptFragment> fragments = script.fragments;
+ if (fragments.length < 1) {
+ throw new AnalysisException('Cannot scan scripts with no fragments');
+ } else if (fragments.length > 1) {
+ throw new AnalysisException(
+ 'Cannot scan scripts with multiple fragments');
+ }
+ ScriptFragment fragment = fragments[0];
+
+ Scanner scanner = new Scanner(
+ source,
+ new SubSequenceReader(fragment.content, fragment.offset),
+ errorListener);
+ scanner.setSourceStart(fragment.line, fragment.column);
+ scanner.preserveComments = context.analysisOptions.preserveComments;
+
+ outputs[TOKEN_STREAM] = scanner.tokenize();
+ outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
+ outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ } else if (target is Source) {
+ String content = getRequiredInput(CONTENT_INPUT_NAME);
+
+ Scanner scanner =
+ new Scanner(source, new CharSequenceReader(content), errorListener);
+ scanner.preserveComments = context.analysisOptions.preserveComments;
+
+ outputs[TOKEN_STREAM] = scanner.tokenize();
+ outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
+ outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ } else {
+ throw new AnalysisException(
+ 'Cannot scan Dart code from a ${target.runtimeType}');
+ }
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ if (target is Source) {
+ return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(target)};
+ } else if (target is DartScript) {
+ // This task does not use the following input; it is included only to add
+ // a dependency between this value and the containing source so that when
+ // the containing source is modified these results will be invalidated.
+ return <String, TaskInput>{'-': DART_SCRIPTS.of(target.source)};
+ }
+ throw new AnalysisException(
+ 'Cannot build inputs for a ${target.runtimeType}');
+ }
+
+ /**
+ * 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 name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_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);
+ //
+ // Prepare inputs.
+ //
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ LibraryElement libraryElement = unitElement.library;
+ //
+ // Validate the directives.
+ //
+ validateDirectives(unit);
+ //
+ // Use the ConstantVerifier to compute errors.
+ //
+ ConstantVerifier constantVerifier = new ConstantVerifier(
+ errorReporter, libraryElement, typeProvider, context.declaredVariables);
+ unit.accept(constantVerifier);
+ //
+ // Use the ErrorVerifier to compute errors.
+ //
+ ErrorVerifier errorVerifier = new ErrorVerifier(
+ errorReporter,
+ libraryElement,
+ typeProvider,
+ new InheritanceManager(libraryElement),
+ context.analysisOptions.enableSuperMixins);
+ unit.accept(errorVerifier);
+ //
+ // Record outputs.
+ //
+ outputs[VERIFY_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ }
+
+ /**
+ * Check each directive in the given [unit] to see if the referenced source
+ * exists and report an error if it does not.
+ */
+ void validateDirectives(CompilationUnit unit) {
+ for (Directive directive in unit.directives) {
+ if (directive is UriBasedDirective) {
+ validateReferencedSource(directive);
+ }
+ }
+ }
+
+ /**
+ * Check the given [directive] to see if the referenced source exists and
+ * report an error if it does not.
+ */
+ void validateReferencedSource(UriBasedDirective directive) {
+ Source source = directive.source;
+ if (source != null) {
+ if (context.exists(source)) {
+ return;
+ }
+ } else {
+ // Don't report errors already reported by ParseDartTask.resolveDirective
+ if (directive.validate() != null) {
+ return;
+ }
+ }
+ StringLiteral uriLiteral = directive.uri;
+ errorReporter.reportErrorForNode(CompileTimeErrorCode.URI_DOES_NOT_EXIST,
+ uriLiteral, [directive.uriContent]);
+ }
+
+ /**
+ * 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(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ 'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE
+ .of(unit.library)
+ .toMapOf(UNITS)
+ .toFlattenList((Source library, Source unit) =>
+ RESOLVED_UNIT.of(new LibrarySpecificUnit(library, unit))),
+ UNIT_INPUT: RESOLVED_UNIT.of(unit),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
+ };
+ }
+
+ /**
+ * 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].
+ *
+ * [resultDescriptor] is the type of result which should be produced for each
+ * target [Source].
+ */
+class _ExportSourceClosureTaskInput extends TaskInputImpl<List<Source>> {
+ final Source target;
+ final ResultDescriptor resultDescriptor;
+
+ _ExportSourceClosureTaskInput(this.target, this.resultDescriptor);
+
+ @override
+ TaskInputBuilder<List<Source>> createBuilder() =>
+ new _SourceClosureTaskInputBuilder(
+ target, _SourceClosureKind.EXPORT, resultDescriptor);
+}
+
+/**
+ * A [TaskInput] whose value is a list of library sources imported or exported,
+ * directly or indirectly by the target [Source].
+ *
+ * [resultDescriptor] is the type of result which should be produced for each
+ * target [Source].
+ */
+class _ImportExportSourceClosureTaskInput extends TaskInputImpl<List<Source>> {
+ final Source target;
+ final ResultDescriptor resultDescriptor;
+
+ _ImportExportSourceClosureTaskInput(this.target, this.resultDescriptor);
+
+ @override
+ TaskInputBuilder<List<Source>> createBuilder() =>
+ new _SourceClosureTaskInputBuilder(
+ target, _SourceClosureKind.IMPORT_EXPORT, resultDescriptor);
+}
+
+/**
+ * A [TaskInput] whose value is a list of library sources imported directly
+ * or indirectly by the target [Source].
+ *
+ * [resultDescriptor] is the type of result which should be produced for each
+ * target [Source].
+ */
+class _ImportSourceClosureTaskInput extends TaskInputImpl<List<Source>> {
+ final Source target;
+ final ResultDescriptor resultDescriptor;
+
+ _ImportSourceClosureTaskInput(this.target, this.resultDescriptor);
+
+ @override
+ TaskInputBuilder<List<Source>> createBuilder() =>
+ new _SourceClosureTaskInputBuilder(
+ target, _SourceClosureKind.IMPORT, resultDescriptor);
+}
+
+/**
+ * The kind of the source closure to build.
+ */
+enum _SourceClosureKind { IMPORT, EXPORT, IMPORT_EXPORT }
+
+/**
+ * A [TaskInputBuilder] to build values for [_ImportSourceClosureTaskInput].
+ */
+class _SourceClosureTaskInputBuilder implements TaskInputBuilder<List<Source>> {
+ final _SourceClosureKind kind;
+ final Set<LibraryElement> _libraries = new HashSet<LibraryElement>();
+ final List<Source> _newSources = <Source>[];
+
+ @override
+ final ResultDescriptor currentResult;
+
+ Source currentTarget;
+
+ _SourceClosureTaskInputBuilder(
+ Source librarySource, this.kind, this.currentResult) {
+ _newSources.add(librarySource);
+ }
+
+ @override
+ void set currentValue(Object value) {
+ LibraryElement library = value;
+ if (_libraries.add(library)) {
+ if (kind == _SourceClosureKind.IMPORT ||
+ kind == _SourceClosureKind.IMPORT_EXPORT) {
+ for (ImportElement importElement in library.imports) {
+ Source importedSource = importElement.importedLibrary.source;
+ _newSources.add(importedSource);
+ }
+ }
+ if (kind == _SourceClosureKind.EXPORT ||
+ kind == _SourceClosureKind.IMPORT_EXPORT) {
+ for (ExportElement exportElement in library.exports) {
+ Source exportedSource = exportElement.exportedLibrary.source;
+ _newSources.add(exportedSource);
+ }
+ }
+ }
+ }
+
+ @override
+ List<Source> get inputValue {
+ return _libraries.map((LibraryElement library) => library.source).toList();
+ }
+
+ @override
+ void currentValueNotAvailable() {
+ // Nothing needs to be done. moveNext() will simply go on to the next new
+ // source.
+ }
+
+ @override
+ bool moveNext() {
+ if (_newSources.isEmpty) {
+ return false;
+ }
+ currentTarget = _newSources.removeLast();
+ return true;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698