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;
}