Question

I am writing a custom FxCop (Code Analysis) rule using the FxCop API.

What I want to achieve is the following:

  1. Find fields which have as declaringtype a Struct.
  2. If the struct has a "StructLayoutAttribute", ignore the field.
  3. If the field is not read-only, add a new problem.

The basics are working correctly, I just can't seem to figure out how to check if the declaringtype has the StructLayoutAttribute or not.

It so happens that the StructLayoutAttribute is not defined in the FxCop API. How would I go about finding it then?

Some sample(C#)-code:

public override ProblemCollection Check(Member member)
{
    Field field = member as Field;
    if (field == null)
        return null;
    if (field.DeclaringType.NodeType != NodeType.Struct)
        return null;        
    //Possibly something like: if(field.DeclaringType.Attributes .....
    // return null;
    if (!field.IsInitOnly)
    {
        Resolution resolution = GetResolution(field, field.DeclaringType);
        Problems.Add(new Problem(resolution));
    }
    return Problems;
}

Addition: This should get ignored.

[StructLayout(LayoutKind.Sequential)]
private struct MXRecord
{
    public IntPtr Next;
    public string Name;
    public short Type;
    public short DataLength;
    public int Flags;
    public int Ttl;
    public int Reserved;
    public IntPtr NameExchange;
    public short Preference;
    public short Pad;
}

And this should NOT.

private struct MXRecord
{
    public IntPtr Next;
    public string Name;
    public short Type;
    public short DataLength;
    public int Flags;
    public int Ttl;
    public int Reserved;
    public IntPtr NameExchange;
    public short Preference;
    public short Pad;
}

What I tried (as suggested) is the following:

StructLayoutAttributeType = FrameworkAssemblies.Mscorlib.GetType(Identifier.For("System.Runtime.InteropServices"),Identifier.For("StructLayoutAttribute"));

Field field = member as Field;
if (field == null)
    return null;
if (field.DeclaringType.NodeType != NodeType.Struct)
    return null;
AttributeNode structLayoutAttrib = field.DeclaringType.GetAttribute(StructLayoutAttributeType);

if (structLayoutAttrib != null)
    return null;
if (!field.IsInitOnly)
{
    Resolution resolution = GetResolution(field, field.DeclaringType);
    Problems.Add(new Problem(resolution));
}
return Problems;
Was it helpful?

Solution

There are two main problems here. The first is with your use of the field's DeclaringType property instead of its Type property. DeclaringType refers to the type in which the field is declared, which doesn't seem to be what you want to examine. For example, in

public class Foo
{
    private Bar _bar;
}

_bar's DeclaringType is Foo, but its Type is Bar.

Unfortunately, fixing this won't resolve the bigger problem, which is that StructLayoutAttribute is a special attribute that doesn't actually make it into the generated IL as a custom attribute. The compiled struct will always be marked as having a sequential, explicit, or auto layout, but this is done using the type header, not by conserving the StructLayoutAttribute in the IL. If the source code did not include a StructLayoutAttribute, the compiled struct will be marked as having a sequential layout.

What this ultimately means for your rule is that it can't be written against the IL unless what you actually care about is the kind of layout as opposed to the presence of the attribute. If the presence of the attribute really is relevant to you, a tool that examines the source code (e.g.: StyleCop) would be a more suitable choice.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top