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

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

Issue 1029953002: Task: BuildClassConstructorsTask. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: add TODO 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 | « pkg/analyzer/lib/src/generated/element.dart ('k') | pkg/analyzer/test/src/task/dart_test.dart » ('j') | no next file with comments »
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 9e5bbf63f7525c73ee27f11a298e21ea480ff2b5..4bce5a2e636b3567358210bd0ef95c561bf65522 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -5,6 +5,7 @@
library analyzer.src.task.dart;
import 'dart:collection';
+import 'dart:math' as math;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
@@ -67,6 +68,23 @@ final ResultDescriptor<List<ClassElement>> CLASS_ELEMENTS =
new ResultDescriptor<List<ClassElement>>('CLASS_ELEMENTS', null);
/**
+ * The [ConstructorElement]s of a [ClassElement].
+ */
+final ResultDescriptor<List<ConstructorElement>> CONSTRUCTORS =
+ new ResultDescriptor<List<ConstructorElement>>('CONSTRUCTORS', null);
+
+/**
+ * The errors produced while building a [ClassElement] constructors.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for targets representing a [ClassElement].
+ */
+final ResultDescriptor<List<AnalysisError>> CONSTRUCTORS_ERRORS =
+ new ResultDescriptor<List<AnalysisError>>(
+ 'CONSTRUCTORS_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
* The sources representing the export closure of a library.
*
* The result is only available for targets representing a Dart library.
@@ -189,6 +207,226 @@ final ResultDescriptor<TypeProvider> TYPE_PROVIDER =
new ResultDescriptor<TypeProvider>('TYPE_PROVIDER', null);
/**
+ * A task that builds implicit constructors for a [ClassElement], or keeps
+ * the existing explicit constructors if the class has them.
+ */
+class BuildClassConstructorsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [CONSTRUCTORS] input for the superclass.
+ */
+ static const String SUPER_CONSTRUCTORS = 'SUPER_CONSTRUCTORS';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'BuildConstructorsForClassTask', createTask, buildInputs,
+ <ResultDescriptor>[CONSTRUCTORS, CONSTRUCTORS_ERRORS]);
+
+ BuildClassConstructorsTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ List<AnalysisError> errors = <AnalysisError>[];
+ //
+ // Prepare inputs.
+ //
+ ClassElementImpl classElement = this.target;
+ List<ConstructorElement> superConstructors = inputs[SUPER_CONSTRUCTORS];
+ DartType superType = classElement.supertype;
+ ClassElement superElement = superType.element;
+ //
+ // Shortcut for ClassElement(s) without implicit constructors.
+ //
+ if (superConstructors == null) {
+ outputs[CONSTRUCTORS] = classElement.constructors;
+ outputs[CONSTRUCTORS_ERRORS] = AnalysisError.NO_ERRORS;
+ return;
+ }
+ //
+ // ClassTypeAlias
+ //
+ if (classElement.isTypedef) {
+ List<ConstructorElement> implicitConstructors =
+ new List<ConstructorElement>();
+ void callback(ConstructorElement explicitConstructor,
+ List<DartType> parameterTypes, List<DartType> argumentTypes) {
+ implicitConstructors.add(_createImplicitContructor(classElement.type,
+ explicitConstructor, parameterTypes, argumentTypes));
+ }
+ if (_findForwardedConstructors(classElement, superType, callback)) {
+ if (implicitConstructors.isEmpty) {
+ errors.add(new AnalysisError.con2(classElement.source,
+ classElement.nameOffset, classElement.name.length,
+ CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
+ [superElement.name]));
+ } else {
+ classElement.constructors = implicitConstructors;
+ }
+ }
+ outputs[CONSTRUCTORS] = classElement.constructors;
+ outputs[CONSTRUCTORS_ERRORS] = errors;
+ }
+ //
+ // ClassDeclaration
+ //
+ if (!classElement.isTypedef) {
+ bool constructorFound = false;
+ void callback(ConstructorElement explicitConstructor,
+ List<DartType> parameterTypes, List<DartType> argumentTypes) {
+ constructorFound = true;
+ }
+ if (_findForwardedConstructors(classElement, superType, callback) &&
+ !constructorFound) {
+ SourceRange withRange = classElement.withClauseRange;
+ errors.add(new AnalysisError.con2(classElement.source, withRange.offset,
+ withRange.length, CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
+ [superElement.name]));
+ classElement.mixinErrorsReported = true;
+ }
+ outputs[CONSTRUCTORS] = classElement.constructors;
+ outputs[CONSTRUCTORS_ERRORS] = errors;
+ }
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [classElement].
+ */
+ static Map<String, TaskInput> buildInputs(ClassElement classElement) {
+ // TODO(scheglov) Here we implicitly depend on LIBRARY_ELEMENT5, i.e. that
+ // "supertype" for the "classElement" is set.
+ // We need to make it an explicit dependency.
+ DartType superType = classElement.supertype;
+ if (superType is InterfaceType) {
+ if (classElement.isTypedef || classElement.mixins.isNotEmpty) {
+ ClassElement superElement = superType.element;
+ return <String, TaskInput>{
+ SUPER_CONSTRUCTORS: CONSTRUCTORS.inputFor(superElement)
+ };
+ }
+ }
+ // No implicit constructors, no inputs required.
+ return <String, TaskInput>{};
+ }
+
+ /**
+ * Create a [BuildClassConstructorsTask] based on the given
+ * [target] in the given [context].
+ */
+ static BuildClassConstructorsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new BuildClassConstructorsTask(context, target);
+ }
+
+ /**
+ * Create an implicit constructor that is copied from the given
+ * [explicitConstructor], but that is in the given class.
+ *
+ * [classType] - the class in which the implicit constructor is defined.
+ * [explicitConstructor] - the constructor on which the implicit constructor
+ * is modeled.
+ * [parameterTypes] - the types to be replaced when creating parameters.
+ * [argumentTypes] - the types with which the parameters are to be replaced.
+ */
+ static ConstructorElement _createImplicitContructor(InterfaceType classType,
+ ConstructorElement explicitConstructor, List<DartType> parameterTypes,
+ List<DartType> argumentTypes) {
+ ConstructorElementImpl implicitConstructor =
+ new ConstructorElementImpl(explicitConstructor.name, -1);
+ implicitConstructor.synthetic = true;
+ implicitConstructor.redirectedConstructor = explicitConstructor;
+ implicitConstructor.const2 = explicitConstructor.isConst;
+ implicitConstructor.returnType = classType;
+ List<ParameterElement> explicitParameters = explicitConstructor.parameters;
+ int count = explicitParameters.length;
+ if (count > 0) {
+ List<ParameterElement> implicitParameters =
+ new List<ParameterElement>(count);
+ for (int i = 0; i < count; i++) {
+ ParameterElement explicitParameter = explicitParameters[i];
+ ParameterElementImpl implicitParameter =
+ new ParameterElementImpl(explicitParameter.name, -1);
+ implicitParameter.const3 = explicitParameter.isConst;
+ implicitParameter.final2 = explicitParameter.isFinal;
+ implicitParameter.parameterKind = explicitParameter.parameterKind;
+ implicitParameter.synthetic = true;
+ implicitParameter.type =
+ explicitParameter.type.substitute2(argumentTypes, parameterTypes);
+ implicitParameters[i] = implicitParameter;
+ }
+ implicitConstructor.parameters = implicitParameters;
+ }
+ FunctionTypeImpl type = new FunctionTypeImpl.con1(implicitConstructor);
+ type.typeArguments = classType.typeArguments;
+ implicitConstructor.type = type;
+ return implicitConstructor;
+ }
+
+ /**
+ * Find all the constructors that should be forwarded from the given
+ * [superType], to the class or mixin application [classElement],
+ * and pass information about them to [callback].
+ *
+ * Return true if some constructors were considered. (A false return value
+ * can only happen if the supeclass is a built-in type, in which case it
+ * can't be used as a mixin anyway).
+ */
+ static bool _findForwardedConstructors(ClassElementImpl classElement,
+ InterfaceType superType, void callback(
+ ConstructorElement explicitConstructor, List<DartType> parameterTypes,
+ List<DartType> argumentTypes)) {
+ ClassElement superclassElement = superType.element;
+ List<ConstructorElement> constructors = superclassElement.constructors;
+ int count = constructors.length;
+ if (count == 0) {
+ return false;
+ }
+ List<DartType> parameterTypes =
+ TypeParameterTypeImpl.getTypes(superType.typeParameters);
+ List<DartType> argumentTypes = _getArgumentTypes(superType, parameterTypes);
+ for (int i = 0; i < count; i++) {
+ ConstructorElement explicitConstructor = constructors[i];
+ if (!explicitConstructor.isFactory &&
+ classElement.isSuperConstructorAccessible(explicitConstructor)) {
+ callback(explicitConstructor, parameterTypes, argumentTypes);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return a list of argument types that corresponds to the [parameterTypes]
+ * and that are derived from the type arguments of the given [superType].
+ */
+ static List<DartType> _getArgumentTypes(
+ InterfaceType superType, List<DartType> parameterTypes) {
+ DynamicTypeImpl dynamic = DynamicTypeImpl.instance;
+ int parameterCount = parameterTypes.length;
+ List<DartType> types = new List<DartType>(parameterCount);
+ if (superType == null) {
+ types = new List<DartType>.filled(parameterCount, dynamic);
+ } else {
+ List<DartType> typeArguments = superType.typeArguments;
+ int argumentCount = math.min(typeArguments.length, parameterCount);
+ for (int i = 0; i < argumentCount; i++) {
+ types[i] = typeArguments[i];
+ }
+ for (int i = argumentCount; i < parameterCount; i++) {
+ types[i] = dynamic;
+ }
+ }
+ return types;
+ }
+}
+
+/**
* A task that builds a compilation unit element for a single compilation unit.
*/
class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask {
« no previous file with comments | « pkg/analyzer/lib/src/generated/element.dart ('k') | pkg/analyzer/test/src/task/dart_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698