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

Unified Diff: pkg/analyzer/lib/src/task/dart.dart

Issue 994293002: Task: Build Library Element Model (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rename BUILT_LIBRARY_ELEMENT. Better tests for inputs. Created 5 years, 9 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
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/task/general.dart » ('j') | pkg/analyzer/lib/task/dart.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..870baf1c80e1d1b20ad3c42b02bc5a701f320546 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,260 @@ 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 compiltion unit of a library.
Brian Wilkerson 2015/03/11 14:16:01 "compiltion" --> "compilation"
scheglov 2015/03/11 16:55:07 Done.
+ */
+ 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 String ENTRY_POINT_NAME = "main";
Brian Wilkerson 2015/03/11 14:16:01 Perhaps this should be moved to FunctionElement so
scheglov 2015/03/11 16:55:06 Will do in the next CL.
+
+ /**
+ * 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) {
+ PropertyInducingElementImpl variable = getter.variable;
+ variable.setter = setter;
+ setter.variable = variable;
Brian Wilkerson 2015/03/11 14:16:01 I think we need to remove the setter's previous va
scheglov 2015/03/11 16:55:06 Done.
+ }
+ }
+ }
+
+ /**
+ * 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 {
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/task/general.dart » ('j') | pkg/analyzer/lib/task/dart.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698