Page 7 of 10               << Previous  1  2  3  4  5  6  7  8  9  10  Next >>

 

Custom FxCop Rule - Remove Empty Methods

This FxCop rule checks for empty methods and recommends removing them or commenting them out. An empty method can be a Sub, Function or Property in Visual Basic or any type of method in C#, with either no code or where all its code is commented out.

To find such methods, we need to examine the MSIL and look for a specific sequence of Opcode instructions.

C# code for custom FxCop rule:

//
// Description: 
//  Enforces the rule that empty void methods (Subs in VB), non-void
//  methods (Functions in VB), and Set properties should be commented 
//  out or removed.
//
//  Example: The following VB / C# methods will be caught:
//
//    <Public | Private...> Sub mySub(<optional parameter list>)
//      ' No code statements or all statements commented out.
//    End Sub
//
//    <public | private...> void mySub(<optional parameters list>) 
//    {
//      // No code statements or all statements commented out.
//    }
//
//    <Public | Private...> Function myFunc(<optional parameter list>) as <type>
//      ' No code statements, no Return, or all statements commented out.
//    End Sub
//
//    <public | private...> <type> myFunc(<optional parameters list>) 
//    {
//      // No code statements, no return, or all statements commented out.
//    }
//
//    NOTE: if a return statement is present, the method is valid even if
//          the return statement is the only valid line of code.    
//
//
//   <Public | Private...> <WriteOnly> Property myProp(ByVal someParm As <type>) As <type>
//      Set(ByVal value As <type>)
//        ' No code statements or all statements commented out.
//      End Set
//   End Property
//
//   <Public | Private...> Property myProp(ByVal someParm As <type>) As <type>
//        Get
//            Return <type>
//        End Get
//        ' Not needed
//        Set(ByVal value As <type>)
//        ' No code statements or all statements commented out.
//        End Set
//   End Property
//
//   <public | private...> <type> myProp 
//   {
//      get { return <type>; }
//      set { "No code statements or all statements commented out" }
//   }
//
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Cci;
using Microsoft.FxCop.Sdk;
using Microsoft.FxCop.Sdk.Introspection;

public class RemoveEmptyMethods : BaseMigrationIntrospectionRule
{
    public RemoveEmptyMethods() : base("RemoveEmptyMethods")
    {
    }

    public override ProblemCollection Check(Member member)
    {
       // Method is a subtype of Member.
       Method method = member as Method;

       if (method == null)
           return base.Check(member);

       //
       // Number of instructions in the method. Method's name.
       //
       InstructionList ops = method.Instructions;
       string methodName = method.Name.Name.ToUpper();

       //
       // If the method doesn't have any opcodes, no analysis is needed.
       //
       if (ops.Length.Equals(0)) 
           return base.Check(member); 

       //
       // Dont bother with default constructors. 
       // Default constructor does nothing except  call the constructor
       // in  its base class. It is usually inserted into an assembly by
       // the compiler.
       //
       if (methodName == ".CTOR" && IsDefaultCtor(method))
          return base.Check(member);
        
       //if (isEmptyFunctionOrGetProperty(method)) 
       //   return base.Check(member); 
       
       //
       // Check for empty methods (Subs), functions, properties. 
       //
       if (isEmptyVoidMethodOrSetProperty(method) || isEmptyNonVoidMethod(method) ) 
       { 
          // For testing purposes, uncomment to print out opcodes.
          //string opcodes == ""; 
          //for (int i = 0;  i <  ops.Length; i++)
          //{
          //    opcodes += ops[i].OpCode.ToString();
          //}
          //base.Problems.Add(new Problem(GetResolution(
          //      method.Name.FullName, 
          //      method.FullName + " ops:" + ops.Length.ToString() + " opcodes: " + opcodes), 
          //      method));
          base.Problems.Add(new Problem(GetResolution(method.FullName), method));
       }
       return base.Problems;
    }
    
    //
    // See if the method is a default constructor - constructor that does nothing 
    // except call the constructor in its base class, usually inserted into your 
    // assemblies by the compiler.
    //
    private bool IsDefaultCtor(Method method)
    {
        InstructionList ops = method.Instructions;

        if (ops.Length.Equals(4))
        {
            //
            // Filter out default ctor generated by the compiler.
            //
            LocalList localList = ops[0].Value as LocalList;

            if (localList != null && localList.Length != 0) return false;
            if (ops[1].OpCode != OpCode.Ldarg_0) return false;
            if (ops[2].OpCode != OpCode.Call) return false;

            InstanceInitializer init = ops[2].Value as InstanceInitializer;

            if (init == null) return false;
            if (ops[3].OpCode != OpCode.Ret) return false;

            return true;
        }
        return false;
    }


    //
    // Checks if the method is an method or 'set' property. 
    // See examples in header comment.
    //
    private bool isEmptyVoidMethodOrSetProperty(Method method)
    {
        InstructionList ops = method.Instructions;

        if (!ops.Length.Equals(4))
            return false;

        if ((ops[0].OpCode == OpCode._Locals) &&
                (ops[1].OpCode == OpCode.Nop) &&
                (ops[2].OpCode == OpCode.Nop) &&
                (ops[3].OpCode == OpCode.Ret))
        {
            return true;
        }
        return false;
    }

    //
    // Checks if the method is an empty function. See examples
    // in header comment.
    //
    private bool isEmptyNonVoidMethod(Method method)
    {
        InstructionList ops = method.Instructions;

        if (!ops.Length.Equals(4))
            return false;

        if ((ops[0].OpCode == OpCode._Locals) &&
            (ops[1].OpCode == OpCode.Nop) &&
            (ops[2].OpCode == OpCode.Ldloc_0) &&
            (ops[3].OpCode == OpCode.Ret))
        {
            return true;
        }
        return false;
    }


    //
    // Checks if the method is an empty function. See examples
    // in header comment.
    //
    private bool isEmptyFunctionOrGetProperty(Method method)
    {
        InstructionList ops = method.Instructions;

        if (!ops.Length.Equals(7))
            return false;

        //
        // Don't care about ops[2].OpCode which will be some 
        // type of load instruction, e.g. OpCode.ldxxx.
        //
        // Opcode 5 returns a value so there is no way of knowing
        // if this is a valid function or not.
        //
        if ((ops[0].OpCode == OpCode._Locals) &&
            (ops[1].OpCode == OpCode.Nop) &&
            (ops[3].OpCode == OpCode.Stloc_0) &&
            (ops[4].OpCode == OpCode.Br_S) &&
            (ops[5].OpCode == OpCode.Ldloc_0) &&
            (ops[6].OpCode == OpCode.Ret))
        {
            return true;
        }
        return false;
    }
}

Rule definition in the XML rules file:

<Rule TypeName="RemoveEmptyMethods" 
          Category="VBMigration" CheckId="AA1001">
    <Name>
        Remove all empty methods and properties
    </Name>
    <Description>
        Empty methods and properties should be commented or removed.
    </Description>
    <Url>
        http://www.thescarms.com/
    </Url>
    <Resolution>
        All empty methods, functions, and 'set' properties should be commented 
        out or removed. Empty method: '{0}'.
    </Resolution>
    <MessageLevel Certainty="99">
        Warning
    </MessageLevel>
    <FixCategories>
        NonBreaking
    </FixCategories>
    <Owner />
<Rule>

 

Page 7 of 10               << Previous  1  2  3  4  5  6  7  8  9  10  Next >>




About TheScarms
About TheScarms


Sample code
version info

If you use this code, please mention "www.TheScarms.com"

Email this page


© Copyright 2024 TheScarms
Goto top of page