Various constructors to ArgumentException
have a paramName parameter. Typically, a
String naming one of the calling method's
parameters should be passed as this argument. As a special case, when the
ArgumentException is constructed in a property, the
paramName should be the property's name.
The implementation makes a call to
VisitStatements, which recursively examines all
of the expressions contained in the member, to find invocations of the
constructor of ArgumentException or the constructor
of a class that inherits from
ArgumentException.
Rule XML:
<Rule TypeName="ArgumentExceptionParameterNaming" Category="Tutorial" CheckId="TT1040"> <Name>ArgumentException constructor's paramName parameter should be a parameter name</Name> <Description> When an ArgumentException is constructed by a constructor that takes paramName, that paramName should be the name of a calling method's parameter, or the name of the property if called in a property setter. </Description> <Url></Url> <Resolution Name="Method">Pass the correct parameter name instead of '{0}'.</Resolution> <Resolution Name="Property">Pass '{0}' as the paramName argument.</Resolution> <MessageLevel Certainty="95">Warning</MessageLevel> <Email></Email> <FixCategories>NonBreaking</FixCategories> <Owner></Owner> </Rule>
Rule Implementation:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.FxCop.Sdk;
namespace TutorialRules
{
public class ArgumentExceptionParameterNaming : BaseIntrospectionRule
{
private Member m_CurrentMember;
private TypeNode m_ArgumentException;
public ArgumentExceptionParameterNaming() :
base("ArgumentExceptionParameterNaming", "TutorialRules.TutorialRules",
typeof(ArgumentExceptionParameterNaming).Assembly)
{
}
public override void BeforeAnalysis()
{
m_ArgumentException = FrameworkAssemblies.Mscorlib.GetType(
Identifier.For("System"), Identifier.For("ArgumentException"));
}
public override ProblemCollection Check(Member member)
{
if (member is Method)
{
m_CurrentMember = member;
VisitStatements(((Method)member).Body.Statements);
}
else if (member is PropertyNode)
{
PropertyNode propNode = (PropertyNode)member;
if (propNode.Setter != null)
{
m_CurrentMember = member;
VisitStatements(propNode.Setter.Body.Statements);
}
}
return this.Problems;
}
public override void VisitExpression(Expression expression)
{
Construct cnstruct;
InstanceInitializer instInit;
int i = 0;
cnstruct = expression as Construct;
if (cnstruct == null)
return;
if (!cnstruct.Type.IsAssignableTo(m_ArgumentException))
return;
instInit = (InstanceInitializer)((MemberBinding)cnstruct.Constructor).BoundMember;
foreach (Expression operand in cnstruct.Operands)
{
if (instInit.Parameters[i].Name.Name == "paramName")
{
Literal lit;
String litString;
lit = operand as Literal;
if (lit == null)
continue;
litString = lit.Value as String;
if (litString == null)
continue;
if (m_CurrentMember is Method)
{
bool found = false;
foreach (Parameter param in ((Method)m_CurrentMember).Parameters)
{
if (param.Name.Name == litString)
{
found = true;
break;
}
}
if (!found)
this.Problems.Add(new Problem(this.GetNamedResolution("Method", litString)));
}
else // m_CurrentMember is PropertyNode
{
if (m_CurrentMember.Name.Name != litString)
this.Problems.Add(new Problem(this.GetNamedResolution("Property", litString)));
}
}
i += 1;
}
}
}
}