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
Sample code version info
|