| Index: pkg/analyzer/lib/src/task/dart.dart
|
| diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
|
| index 5fd3c1dbf3227d3a828005f644ab53b0c30f6aa1..9b8ca0b06db1ffad5f96024d3a317ff62fc01e3a 100644
|
| --- a/pkg/analyzer/lib/src/task/dart.dart
|
| +++ b/pkg/analyzer/lib/src/task/dart.dart
|
| @@ -14,8 +14,10 @@ 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/general.dart';
|
| +import 'package:analyzer/src/task/inputs.dart';
|
| import 'package:analyzer/task/dart.dart';
|
| import 'package:analyzer/task/general.dart';
|
| import 'package:analyzer/task/model.dart';
|
| @@ -86,6 +88,263 @@ class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask {
|
| }
|
|
|
| /**
|
| + * A task that builds a library element for a Dart library.
|
| + */
|
| +class BuildLibraryElementTask extends SourceBasedAnalysisTask {
|
| + /**
|
| + * The name of the input whose value is the built compilation unit of the
|
| + * defining compilation unit of a library.
|
| + */
|
| + static const String DEFINING_BUILT_UNIT_INPUT_NAME = 'definingBuiltUnit';
|
| +
|
| + /**
|
| + * The name of the input whose value is a list of built compilation units
|
| + * of the parts sourced by a library.
|
| + */
|
| + static const String PART_BUILT_UNITS_INPUT_NAME = 'partBuiltUnits';
|
| +
|
| + /**
|
| + * The name of the function used as an entry point.
|
| + */
|
| + static const String ENTRY_POINT_NAME = "main";
|
| +
|
| + /**
|
| + * The task descriptor describing this kind of task.
|
| + */
|
| + static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
|
| + 'BUILD_LIBRARY_ELEMENT', createTask, buildInputs, <ResultDescriptor>[
|
| + BUILD_LIBRARY_ERRORS,
|
| + BUILT_LIBRARY_ELEMENT,
|
| + IS_LAUNCHABLE,
|
| + HAS_HTML_IMPORT
|
| + ]);
|
| +
|
| + /**
|
| + * 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_BUILT_UNIT_INPUT_NAME);
|
| + List<CompilationUnit> partUnits =
|
| + getRequiredInput(PART_BUILT_UNITS_INPUT_NAME);
|
| + //
|
| + // 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;
|
| + }
|
| + Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML);
|
| + //
|
| + // Update "part" directives.
|
| + //
|
| + LibraryIdentifier libraryNameNode = null;
|
| + bool hasHtmlImport = false;
|
| + bool hasPartDirective = false;
|
| + FunctionElement entryPoint =
|
| + _findEntryPoint(definingCompilationUnitElement);
|
| + List<Directive> directivesToResolve = <Directive>[];
|
| + List<CompilationUnitElementImpl> sourcedCompilationUnits =
|
| + <CompilationUnitElementImpl>[];
|
| + for (Directive directive in definingCompilationUnit.directives) {
|
| + if (directive is ImportDirective) {
|
| + hasHtmlImport = hasHtmlImport || directive.source == htmlSource;
|
| + } else if (directive is LibraryDirective) {
|
| + if (libraryNameNode == null) {
|
| + libraryNameNode = directive.name;
|
| + directivesToResolve.add(directive);
|
| + }
|
| + } else if (directive is PartDirective) {
|
| + PartDirective partDirective = directive;
|
| + StringLiteral partUri = partDirective.uri;
|
| + Source partSource = partDirective.source;
|
| + if (context.exists(partSource)) {
|
| + hasPartDirective = true;
|
| + CompilationUnit partUnit = partUnitMap[partSource];
|
| + CompilationUnitElementImpl partElement = partUnit.element;
|
| + partElement.uriOffset = partUri.offset;
|
| + partElement.uriEnd = partUri.end;
|
| + partElement.uri = partDirective.uriContent;
|
| + //
|
| + // Validate that the part contains a part-of directive with the same
|
| + // name as the library.
|
| + //
|
| + String partLibraryName =
|
| + _getPartLibraryName(partSource, partUnit, directivesToResolve);
|
| + if (partLibraryName == null) {
|
| + errors.add(new AnalysisError.con2(librarySource, partUri.offset,
|
| + partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, [
|
| + partUri.toSource()
|
| + ]));
|
| + } else if (libraryNameNode == null) {
|
| + // TODO(brianwilkerson) Collect the names declared by the part.
|
| + // If they are all the same then we can use that name as the
|
| + // inferred name of the library and present it in a quick-fix.
|
| + // partLibraryNames.add(partLibraryName);
|
| + } else if (libraryNameNode.name != partLibraryName) {
|
| + errors.add(new AnalysisError.con2(librarySource, partUri.offset,
|
| + partUri.length, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [
|
| + libraryNameNode.name,
|
| + partLibraryName
|
| + ]));
|
| + }
|
| + if (entryPoint == null) {
|
| + entryPoint = _findEntryPoint(partElement);
|
| + }
|
| + directive.element = partElement;
|
| + sourcedCompilationUnits.add(partElement);
|
| + }
|
| + }
|
| + }
|
| + if (hasPartDirective && libraryNameNode == null) {
|
| + errors.add(new AnalysisError.con1(librarySource,
|
| + ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
|
| + }
|
| + //
|
| + // Create and populate the library element.
|
| + //
|
| + LibraryElementImpl libraryElement =
|
| + new LibraryElementImpl.forNode(context, libraryNameNode);
|
| + libraryElement.definingCompilationUnit = definingCompilationUnitElement;
|
| + libraryElement.entryPoint = entryPoint;
|
| + libraryElement.parts = sourcedCompilationUnits;
|
| + for (Directive directive in directivesToResolve) {
|
| + directive.element = libraryElement;
|
| + }
|
| + if (sourcedCompilationUnits.isNotEmpty) {
|
| + _patchTopLevelAccessors(libraryElement);
|
| + }
|
| + //
|
| + // Record outputs.
|
| + //
|
| + outputs[BUILD_LIBRARY_ERRORS] = errors;
|
| + outputs[BUILT_LIBRARY_ELEMENT] = libraryElement;
|
| + outputs[IS_LAUNCHABLE] = entryPoint != null;
|
| + outputs[HAS_HTML_IMPORT] = hasHtmlImport;
|
| + }
|
| +
|
| + /**
|
| + * 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.name == ENTRY_POINT_NAME) {
|
| + return function;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Return the name of the library that the given part is declared to be a
|
| + * part of, or `null` if the part does not contain a part-of directive.
|
| + */
|
| + String _getPartLibraryName(Source partSource, CompilationUnit partUnit,
|
| + List<Directive> directivesToResolve) {
|
| + for (Directive directive in partUnit.directives) {
|
| + if (directive is PartOfDirective) {
|
| + directivesToResolve.add(directive);
|
| + LibraryIdentifier libraryName = directive.libraryName;
|
| + if (libraryName != null) {
|
| + return libraryName.name;
|
| + }
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Look through all of the compilation units defined for the given [library],
|
| + * looking for getters and setters that are defined in different compilation
|
| + * units but that have the same names. If any are found, make sure that they
|
| + * have the same variable element.
|
| + */
|
| + void _patchTopLevelAccessors(LibraryElementImpl library) {
|
| + HashMap<String, PropertyAccessorElement> getters =
|
| + new HashMap<String, PropertyAccessorElement>();
|
| + List<PropertyAccessorElement> setters = <PropertyAccessorElement>[];
|
| + _collectAccessors(getters, setters, library.definingCompilationUnit);
|
| + for (CompilationUnitElement unit in library.parts) {
|
| + _collectAccessors(getters, setters, unit);
|
| + }
|
| + for (PropertyAccessorElementImpl setter in setters) {
|
| + PropertyAccessorElement getter = getters[setter.displayName];
|
| + if (getter != null) {
|
| + TopLevelVariableElementImpl variable = getter.variable;
|
| + TopLevelVariableElementImpl setterVariable = setter.variable;
|
| + CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement;
|
| + setterUnit.replaceTopLevelVariable(setterVariable, variable);
|
| + variable.setter = setter;
|
| + setter.variable = variable;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Return a map from the names of the inputs of this kind of task to the task
|
| + * input descriptors describing those inputs for a task with the given
|
| + * [target].
|
| + */
|
| + static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
|
| + return <String, TaskInput>{
|
| + DEFINING_BUILT_UNIT_INPUT_NAME: new SimpleTaskInput(target, BUILT_UNIT),
|
| + PART_BUILT_UNITS_INPUT_NAME:
|
| + new ListBasedTaskInput<List<Source>, CompilationUnit>(
|
| + new SimpleTaskInput<List<Source>>(target, INCLUDED_PARTS),
|
| + (Source includedSource) => new SimpleTaskInput<CompilationUnit>(
|
| + includedSource, BUILT_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 parses the content of a Dart file, producing an AST structure.
|
| */
|
| class ParseDartTask extends SourceBasedAnalysisTask {
|
|
|