Caller Info Param Last

ID

csharp.caller_info_param_last

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Best Practice

Language

CSharp

Tags

api_design, attributes, best_practice, parameters

Description

Reports a parameter carrying one of the caller-information attributes — CallerFilePath, CallerLineNumber, CallerMemberName or CallerArgumentExpression — that is followed by a parameter carrying none of them. Both the plain and the Attribute-suffixed spelling are recognised, qualified or not.

Put differently: the caller-information parameters must form the tail of the parameter list.

Rationale

A caller-information attribute is a compile-time favour done to the caller. When the argument is left out, the compiler writes the call site’s own file path, line number, member name or argument text in its place. When the argument is supplied, the attribute is ignored — there is nothing left to fill in.

That makes the position of such a parameter part of its contract. Everything before it has to be written out at the call site, so a caller-information parameter in the middle of the list can only be skipped by naming the arguments that come after it:

using System.Runtime.CompilerServices;

public class Tracer
{
    public void Log([CallerMemberName] string member = "", string message = "") { }   // FLAW

    public void Report(string message, [CallerMemberName] string member = "") { }     // OK
}

// tracer.Log(message: "started");    the only way to let 'member' be filled in
// tracer.Log("started");             compiles, and quietly lands in 'member'

The second call is the one that hurts: it compiles, it looks right, and the message ends up in the parameter that was supposed to record where the call came from — while message takes the empty default. Nothing reports the mistake, and the diagnostic value the parameter was added for is gone.

Remediation

Move every caller-information parameter to the end of the list, after all parameters callers are expected to pass. They already need a default value to be omittable, so the ordering rule for optional parameters is satisfied at the same time. If an existing signature cannot be reordered because callers depend on the current positions, add an overload with the parameters in the right order and leave the old one to delegate to it.