FAQ: How do I get the SourceContext for a local?

I want to fire on the naming of a local, however, whenever I pass the local to the Problem constructor, the source information for the method is always used. How do I get FxCop/Code Analysis to use the source information for the local instead?

Because the declaration of a local is not associated with an executable instruction, a local does not contain any source information within the pdb. However, any usages of the local (such as an assignment) does.

The following example shows when source information is provided and not provided:

    public void Bar()
{
        int value1; // Does not have source information
value1 = 10;               // Has source information
int value2 = 20;           // Has source information

Console.WriteLine(value1); // Has source information
Console.WriteLine(value2); // Has source information
}

As most locals are assigned at their time of declaration (such as in the case of value2 in the above example), a simple trick is use the source context of the first usage of the local in place of its declaration. This works in most situations.

The following example shows this (using the code from FAQ: How do I access the locals of a method in a custom rules?):

    public override ProblemCollection Check(Member member)
{
Method method = member as Method;
if (method == null)
return null;

if (method.Instructions.Length == 0)
return null;

LocalList locals = method.Instructions[0].Value as LocalList;
if (locals == null)
return null;

    for (int i = 0; i < locals.Length; i++)
{
Local local = locals[i];

if (someCondition)
{ // Fire on the local

Resolution resolution = new Resolution("Fix local {0}", local.Name.Name);

                SourceContext sourceContext = FindSourceContext(local, method.Instructions);

                Problem problem = new Problem(resolution, sourceContext);
Problems.Add(problem);
}
}

return Problems;
}

    private static SourceContext FindSourceContext(Local local, InstructionList instructions)
{
foreach (Instruction instruction in instructions)
{
if (instruction.Value == local)
{ // Found its first usage
return instruction.SourceContext;
}
}

return new SourceContext();
}

Note: If the local is only declared and is never assigned to, or its usage is only as the argument for an out parameter, then the source context of the method will be used.