structurizeConstructor function
Future<StructurizeResult>
structurizeConstructor(
- DartType type,
- ConstructorElement constructorElement,
- SubjectGenContext<
Element> context, - CachedAliasCounter counter,
Implementation
Future<StructurizeResult> structurizeConstructor(
DartType type,
ConstructorElement constructorElement,
SubjectGenContext<Element> context,
CachedAliasCounter counter) async {
List<AliasImport> imports = [];
List<IRStructureField> fields = [];
var element = type.element! as ClassElement;
var serialName = element.name;
// Determine used constructor
var constructorName = "";
if (element.getNamedConstructor("dog") != null) {
constructorElement = element.getNamedConstructor("dog")!;
constructorName = ".dog";
}
for (var e in constructorElement.parameters) {
String? fieldName;
DartType? fieldType;
Element? fieldElement;
if (e is FieldFormalParameterElement) {
fieldName = e.name;
fieldType = e.type;
fieldElement = e.field;
} else if (e is SuperFormalParameterElement) {
FieldFormalParameterElement resolveUntilFieldFormal(ParameterElement e) {
if (e is FieldFormalParameterElement) return e;
if (e is SuperFormalParameterElement) {
return resolveUntilFieldFormal(e.superConstructorParameter!);
}
throw Exception("Can't resolve super formal field");
}
var field = resolveUntilFieldFormal(e.superConstructorParameter!).field;
fieldName = field!.name;
fieldType = field.type;
fieldElement = field;
} else {
var parameterType = e.type;
var namedField = element.getField(e.name);
var namedGetter = element.lookUpGetter(e.name, element.library);
if (namedField != null && namedGetter == null) {
fieldName = e.name;
fieldType = namedField.type;
fieldElement = namedField;
if (parameterType.nullabilitySuffix == NullabilitySuffix.question) {
fieldType = parameterType;
}
} else {
if (namedGetter != null) {
fieldName = e.name;
fieldType = namedGetter.returnType;
fieldElement = namedGetter;
if (parameterType.nullabilitySuffix == NullabilitySuffix.question) {
fieldType = parameterType;
}
}
}
}
if (fieldElement == null || fieldName == null || fieldType == null) {
throw Exception(
"Constructor fields must have a backing field or getter with the same name and type. Nullability may vary.");
}
var serialType = await getSerialType(fieldType, context);
var iterableType = await getIterableType(fieldType, context);
var optional = fieldType.nullabilitySuffix == NullabilitySuffix.question;
if (fieldType is DynamicType) optional = true;
var propertyName = fieldName;
if (propertyNameChecker.hasAnnotationOf(fieldElement)) {
var annotation = propertyNameChecker.annotationsOf(fieldElement).first;
propertyName = annotation.getField("name")!.toStringValue()!;
}
var propertySerializer = "null";
if (propertySerializerChecker.hasAnnotationOf(fieldElement)) {
var serializerAnnotation =
propertySerializerChecker.annotationsOf(fieldElement).first;
propertySerializer =
counter.get(serializerAnnotation.getField("type")!.toTypeValue()!);
}
fields.add(IRStructureField(
fieldName,
counter.get(fieldType),
getTypeTree(fieldType).code(counter),
propertySerializer,
counter.get(serialType),
iterableType,
propertyName,
optional,
!isDogPrimitiveType(serialType),
getRetainedAnnotationSourceArray(fieldElement, counter),
mapChecker.isAssignableFrom(fieldType.element!)));
}
// Create proxy arguments
var getters = fields.map((e) => e.accessor).toList();
var activator =
"return ${counter.get(element.thisType)}$constructorName(${constructorElement.parameters.mapIndexed((i, e) {
var y = fields[i];
if (e.isNamed) {
if (y.iterableKind == IterableKind.none) return "${e.name}: list[$i]";
if (y.optional) return "${e.name}: list[$i]?.cast<${y.serialType}>()";
return "${e.name}: list[$i].cast<${y.serialType}>()";
} else {
if (y.iterableKind == IterableKind.none) return "list[$i]";
if (y.optional) return "list[$i]?.cast<${y.serialType}>()";
return "list[$i].cast<${y.serialType}>()";
}
}).join(", ")});";
var isDataclass = dataclassChecker.isAssignableFromType(element.thisType);
var structure = IRStructure(
counter.get(type),
isDataclass ? StructureConformity.dataclass : StructureConformity.basic,
serialName,
fields,
getRetainedAnnotationSourceArray(element, counter));
return StructurizeResult(imports, structure, getters, activator);
}