Search code examples
c#sourcegeneratorscsharp-source-generator

Is there a C# source generator which updates/adds arguments to a function?


I have a function defined as follow public void FunctionA(params object args[])

and I can call it like this FunctionA(1+2, a+b);

Is there a way for source generator to change the call to FunctionA(1+2, a+b, "1+2", "a+b"); ?

Basically, I need to have the input args also as a string before evaluation (similar to CallerArgumentExpression attribute functionality).

Can a source generator change/update existing code or just add a new code?


Solution

  • You cannot do this with source generators. They cannot modify existing code, only add new code.

    Strictly speaking this is possible, in a rather ugly way which is currently in preview (and might yet change / be removed), see Marc's answer or here.

    You can get close to what you want with [CallerArgumentExpression]: this lets you specify an extra parameter which is filled in by the compiler at compile-time:

    This means you could write:

    void FunctionA(object arg, [CallerArgumentExpression("arg")] string? message = null)
    {
    }
    
    FunctionA(a + 1);
    

    And the compiler would insert a string for message at compile-time:

    FunctionA(a + 1, "a + 1");
    

    However, this doesn't seem to play well with params: a params parameter needs to be the last parameter passed to a function, which means you'd need to do this:

    void FunctionA([CallerArgumentExpression("args")] string? message = null, params object[] args)
    {
    }
    

    ... but then you'd have to use named parameters to avoid passing a value for message, and you can't use named parameters with params (sensibly), so that doesn't work.

    You could remove params, and do:

    void FunctionA(object[] args, [CallerArgumentExpression("args")] string? message = null)
    {
    }
    
    FunctionA([a + 1, a + 2]);
    

    ... but then you only have a single message for the whole of args. The compiler inserts the following at compile time:

    FunctionA([a + 1, a + 2], "[a + 1, a + 2]");
    

    ... which probably isn't what you want.

    If you don't mind having multiple overloads for different numbers of parameters, you can do e.g.:

    void FunctionA(
        object arg1,
        object arg2,
        [CallerArgumentExpression("arg1")] string? message1 = null,
        [CallerArgumentExpression("arg2")] string? message2 = null)
    {
    }