Search code examples
c#attributeslanguage-lawyercompile-time

Is CallerMemberNameAttribute guaranteed to be evaluated before inlining?


Here is the documentation for the attribute. It does not mention when it is evaluated.

Here is the documentation for the greater 'CallerInformation' mechanism. It makes the following assertion:

Caller info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the StackTrace property for exceptions, the results aren't affected by obfuscation.

but does not contain any statements as to timing, sequence or explicitly inlining.

Is CallerMemberNameAttribute guaranteed to be set before that caller is inlined?

If not, does a more robust mechanism exist by now?

(I actually want the signature or at least name of the current function, but all instructions to accomplish that go towards "call another function and there use CallerMemberNameAttribute" or to obvious runtime solutions. Not thrilled about the prospect of having to annotate every caller with [MethodImpl(MethodImplOptions.NoInlining)]: It is easy to miss in Code Review and not at all(?) supported by Refactoring tools.)


Solution

  • Inlining is not something the C# compiler does, it happens at a lower level in the JIT (or AOT compiler), so the C# compiler will always emit the value in a normal ldstr and callvirt instruction. In any case, inlining is never allowed to have side-effects, so even if it was inlined it shouldn't have been an issue.

    You can prove this with a simple test that uses MethodImpl.AggressiveInlining, see the results and the decompilation.

    Note also the spec which says:

    21.5.5.4 The CallerMemberName attribute

    The System.Runtime.CompilerServices.CallerMemberNameAttribute is allowed on optional parameters when there is a standard implicit conversion (§10.4.2) from string to the parameter’s type.

    If a function invocation from a location within the body of a function member or within an attribute applied to the function member itself or its return type, parameters or type parameters in source code omits an optional parameter with the CallerMemberNameAttribute, then a string literal representing the name of that member is used as an argument to the invocation instead of the default parameter value.

    So the spec explicitly states that it has to use that value as the parameter, no inlining is allowed.