The purpose of the post is not to show how to create FxCop rules, a nice explanation can be found in this useful blog entry: FxCop This (also useful links are provided).
The rule that I'm going to show is used to detect assignments from a field to itself. For example:
public class AClass {
   int aValue;
   public void AMethod(int aValeu){
      this.aValue = aValue;
      ...
   }
   ...
}
In this example, an error typing the name of the first argument of
AMethod leads to an incorrect assignment of field aValue to itself. The C# compiler gives you a warning on this, however the code is generated because it is a valid program.In order to create an FxCop rule that detects this, we have to identify the IL code sequence that represents the assignment. By using ILDASM we can see this:
.method public hidebysig instance void  AMethod(int32 aValeu) cil managed
{
  // Code size       14 (0xe)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.0
  IL_0003:  ldfld      int32 AClass::aValue
  IL_0008:  stfld      int32 AClass::aValue
  ...
} // end of method AClass::AMethod
So what we need to find is the simple pattern of a LDFLD opcode followed by a STFLD to the same field. The code for this rule looks like this:
type SameFieldAssignment = class
    inherit BaseIntrospectionRule
    new() = {inherit BaseIntrospectionRule("SameFieldAssignment","SameFieldAssignment",Assembly.GetExecutingAssembly());}
    override x.Check(m : Member) =  
       match m with 
          | (:? Method as meth) -> 
                 let instrs = instructions_to_list meth.Instructions
                   in 
                      x.find_assignment instrs
          | _ -> x.Problems 
   
    member x.find_assignment (instructions : Instruction list) =
        match instructions with
           | (load::store::r) when 
                 (load.OpCode  = OpCode.Ldfld && 
                  store.OpCode = OpCode.Stfld && 
                  load.Value = store.Value)
                   -> x.Problems.Add(new Problem(x.GetNamedResolution("SameFieldAssignment",[||]),store.SourceContext))  
                      x.find_assignment r
           | (_::r) -> x.find_assignment r
           | _ -> x.Problems
end
The
find_assignment method is used to search for the desired pattern. The IL code sequence is converted to a F# list (via the instructions_to_list utility function), then a list pattern is the used to identify the desired pattern.We can improve this code by using active patterns. For example we can define the following patterns:
let (|Ldfld|_|) (i : Instruction) = 
   if (i.OpCode = OpCode.Ldfld) then
      Some ((i.Value :?> Field) , i.SourceContext)
   else
      None
let (|Stfld|_|) (i : Instruction) = 
   if (i.OpCode = OpCode.Stfld) then
      Some((i.Value :?> Field),i.SourceContext)
   else
      None
let (|MethodContent|_|) (m : Member) =
    match m with
       | (:? Method as meth) ->
               Some (meth.FullName, 
                     instructions_to_list meth.Instructions)
       | _ -> None
Now we can write:
type SameFieldAssignmentAp = class
    inherit BaseIntrospectionRule
    new() = {inherit BaseIntrospectionRule("SameFieldAssignmentAp","SameFieldAssignmentAp",Assembly.GetExecutingAssembly());}
    override x.Check(m : Member) =  
       match m with 
          | MethodContent(_,instrs) ->  x.find_assignment instrs
          | _ -> x.Problems 
   
    member x.find_assignment (instructions : Instruction list) =
        match instructions with
           | (Ldfld(lField,_)::Stfld(sField,source)::r) when (lField = sField)
                   -> let p = new Problem(x.GetNamedResolution("SameFieldAssignmentAp",[|lField.FullName|]),source) in
                         x.Problems.Add(p)  
                      x.find_assignment r
           | (_::r) -> x.find_assignment r
           | _ -> x.Problems
end
Code for this experiment can be found here.
