generateMethodOverride method
Implementation
Future<List<String>> generateMethodOverride(
MethodElement methodElement,
) async {
TypeInfo returnType = typeMap.fromDartType(
methodElement.returnType,
context: typeArgumentsMap(),
);
List<String> lines = [];
if (elementInjectionType(methodElement) == '@SubtypeFactory') {
if ((methodElement.firstFragment.formalParameters[0].name !=
'className') ||
(methodElement.firstFragment.formalParameters[0].element.type
.getDisplayString() !=
'String')) {
throw Exception(
'SubtypeFactory first argument needs to be named className and be of type String',
);
}
List<String> argsDef = [];
List<String> argsInv = [];
Map<String, TypeInfo> arguments = {};
for (var p in methodElement.firstFragment.formalParameters) {
TypeInfo argType = typeMap.fromDartType(
p.element.type,
context: typeArgumentsMap(),
);
argsDef.add('${argType.uniqueName} ${p.name!}');
argsInv.add(p.name!);
arguments[p.name!] = argType;
}
String factoryInv =
'createSubtypeOf${returnType.flatName}${argsInv.length}(${argsInv.join(',')})';
String factoryDef =
'createSubtypeOf${returnType.flatName}${argsInv.length}(${argsDef.join(',')})';
if (!typeMap.subtypeFactories.containsKey(factoryDef)) {
typeMap.subtypeFactories[factoryDef] = SubtypeFactoryInfo(
returnType,
arguments,
);
}
lines.add('return \$om.$factoryInv;');
} else if (elementInjectionType(methodElement) == '@Factory') {
var best = typeMap.getBestCandidate(returnType);
lines.add('//${returnType.fullName}');
lines.add('return ${best.generateCreator()};');
} else if (elementInjectionType(methodElement) == '@Compile') {
lines.add('//compiled method');
//TODO: add original method if not abstract ??
List<CompiledFieldMethodPart> calledParts = [];
for (var methodPartElement in allMethods()) {
if (methodPartElement.name!.startsWith('_${methodElement.name!}')) {
if (elementInjectionType(methodPartElement) == '@CompilePart') {
String part = await methodPartElement.getSourceCode(typeMap.step);
lines.add(part);
} else if (elementInjectionType(methodPartElement) ==
'@CompileFieldsOfType') {
//var fieldType = typeMap.fromDartType(methodPartElement.parameters.last.type, context:typeArgumentsMap());
if (!typeMap.compiledMethodsByType.containsKey(methodElement)) {
typeMap.compiledMethodsByType[methodElement] = {};
lines.add('//dbg: ${methodElement.name!}');
}
//iterated trough fields with parent first to generate parent bits first and then subclasses bits.
for (var field in allFields(parentFirst: true)) {
var compiledPart =
await CompiledFieldMethodPart.addFieldMethodPart(
this,
methodElement,
methodPartElement,
field,
'dis',
);
if (compiledPart != null && !calledParts.contains(compiledPart)) {
lines.add(compiledPart.getCallExpression('this'));
calledParts.add(compiledPart);
}
}
for (var plugin in plugins) {
for (var field in plugin.allFields()) {
var compiledPart =
await CompiledFieldMethodPart.addFieldMethodPart(
this,
methodElement,
methodPartElement,
field,
'dis.decorated',
);
if (compiledPart != null &&
!calledParts.contains(compiledPart)) {
lines.add(
compiledPart.getCallExpression('this.${plugin.varName}'),
);
calledParts.add(compiledPart);
}
}
}
}
}
}
//lines.add(methodElement.computeNode().body.toSource());
} else {
//check if method has any plugins
Map<MethodElement, TypeInfo> beforePlugins = {};
Map<MethodElement, TypeInfo> afterPlugins = {};
for (var p in plugins) {
p.allMethods().forEach((pluginMethodElement) {
if (elementInjectionType(pluginMethodElement) == '@MethodPlugin') {
if (pluginMethodElement.name ==
"before${methodElement.name!.substring(0, 1).toUpperCase()}${methodElement.name!.substring(1)}") {
beforePlugins[pluginMethodElement] = p;
} else if (pluginMethodElement.name ==
"after${methodElement.name!.substring(0, 1).toUpperCase()}${methodElement.name!.substring(1)}") {
afterPlugins[pluginMethodElement] = p;
}
}
});
}
String paramsStr = methodElement.firstFragment.formalParameters
.map((mp) => mp.name)
.join(",");
String beforeArgsStr = '';
if (beforePlugins.isNotEmpty) {
lines.add('List<dynamic> args = [$paramsStr];');
int i = 0;
beforeArgsStr = methodElement.firstFragment.formalParameters
.map((mp) => "args[${i++}]")
.join(',');
}
for (var pluginMethod in beforePlugins.keys) {
String pluginName = beforePlugins[pluginMethod]!.varName;
lines.add(
'args = ${pluginMethod.firstFragment.isAsynchronous ? 'await' : ''} $pluginName.${pluginMethod.name}($beforeArgsStr);',
);
}
if (beforePlugins.isNotEmpty) {
int i = 0;
for (var mp in methodElement.firstFragment.formalParameters) {
lines.add('${mp.name} = args[$i];');
i++;
}
}
bool isVoid =
(methodElement.returnType is VoidType) ||
(methodElement.returnType.getDisplayString() == 'Future<void>');
if (beforePlugins.length + afterPlugins.length > 0) {
lines.add(
'${!isVoid ? 'var ret = ' : ''}${methodElement.firstFragment.isAsynchronous ? 'await ' : ''}super.${methodElement.name}($paramsStr);',
);
}
for (var pluginMethod in afterPlugins.keys) {
String pluginName = afterPlugins[pluginMethod]!.varName;
//add params to after plugin, TODO: validate if names match original method params
List<String> params = pluginMethod.firstFragment.formalParameters
.map((mp) => mp.name!)
.toList();
if (!isVoid) {
params.first = 'ret';
}
lines.add(
'${!isVoid ? 'ret = ' : ''}${pluginMethod.firstFragment.isAsynchronous ? 'await ' : ''}$pluginName.${pluginMethod.name}(${params.join(',')});',
);
}
if (!isVoid && (beforePlugins.length + afterPlugins.length > 0)) {
lines.add('return ret;');
}
}
return lines;
}