How to access and modify function expression from field?

I’m trying to write a macro which modifies all functions/methods from all compiled classes to inject custom code into them, but I am unable to find a way to even access the Function expression via the field.kind property like how you would do with matching and FVar.

var fields:Array<ClassField> = classType.fields.get();
for (i in 0...fields.length)
{
	var field:ClassField = fields[i];
	switch(field.kind)
	{
		case FieldKind.FMethod(f):
			// `f` only represents the function "kind", it doesn't give any info about the function itself
			// how can i modify the function code here???

		//case FFun(f):   <- can't get function info like this
		//case FVar(t,_)  <- but you can for variables?? why?
		default:
	}
}

You’d have to do this as a build macro. Type Building - Haxe - The Cross-platform Toolkit

Same with FVar, actually. The FVar you get from ClassField is not the same FVar that lets you make modifications.

I see, but is there no way of making this process automatic? I don’t want to have to put a build metadata on every single class in the source code of my game.

You can use --macro addGlobalMetadata('', '@:build(your.Macro.here())) to apply it to all classes - note that this will affect the stdlib too. You can avoid that by using a more restrictive pathFilter, like for example just the root package of your game, if you have one.

Exactly what I needed, thanks! That’s half way there, the second part is modifying the function expression themselves.
I’ve already written the code for getting all the function fields and such but I’m having issues overriding the original function expression because of types. My implementation for expressions which return Void or another type almost work, except for the part that for some reason the compiler thinks some of the return types are of type Void even though the switch that determines if the return type is Void or not correctly shows if the variable is Void or not.

switch (field.kind) {
	case FFun(f):
		var originalExpression = f.expr;

		var isVoid:Bool = switch(f.ret)
		{
			case null:
				true;
			case TPath(a):
				a.name == "Void";
			default:
				false;
		};
					
		if (isVoid)
		{
			f.expr = macro {
				$originalExpression;
			};
		}
		else
		{
			f.expr = macro {
				return $originalExpression;
			};
		}
	default:

When building, some fields throw errors because of the issue described:

hmod/macros/MixMacro.hx:80: characters 8-34 : Void should be Int
hmod/macros/MixMacro.hx:80: characters 8-34 : Void should be Float
hmod/macros/MixMacro.hx:80: characters 8-34 : Void should be Bool
hmod/macros/MixMacro.hx:80: characters 8-34 : Void should be haxe.Int32
hmod/macros/MixMacro.hx:80: characters 8-34 : Void should be String
hmod/macros/MixMacro.hx:80: characters 8-34 : Void should be Dynamic

Sorry for the 3 month late reply, I kind of forgot about this. Thanks for the help so far though!

I have found the source of this issue. Some function fields may throw an error instead of returning the desired Type because the of the path that the program ends up taking does not return anything (aka returns Void) up until the end of the field expression, which at that point causes the macro context to throw the errors I showed. I’m still trying to figure out a fix for this…