Search Amazon:

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 >>

Sign In
  User Id 
  Password 


Submit Your Own Code and Articles




About TheScarms
About TheScarms

Ask me your programming questions

I read every email and answer all I can.

User Feedback: Comments: 1 Items to Show:     

     
Id:  1 Posted:  5/6/2007 4:34:48 PM By:  PSMACCHIA
With the CQL language provided with NDepend, coding this rule is as simple as:
http://www.NDepend.com

WARN IF Count > 0 IN SELECT METHODS WHERE NbLinesOfCode == 0 AND !IsAbstract
 
You must log in to post feedback.
Comment:    
 

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

Email this page


TheScarms AppSentinel lets you securely copy protect and create evaluation versions of your software

TheScarms(tm) AppSentinel lets you quickly and easily create evaluation versions of your software and stop unauthorized copying and unregistered use of your programs!

Get your free
trial copy today!


      The World's Number 1 Web Host

© Copyright 2008 TheScarms