using System;
using System.Collections;
using System.Collections.Specialized;
using AnticipatingMinds.Genesis.KnowledgeManagement;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using System.Windows.Forms;
using System.Xml;
namespace AnticipatingMinds.KnowledgePack.ErrorHandling{
public class TestForNullArgumentBeforeReferencingRuleTemplate : RuleTemplate
{
public TestForNullArgumentBeforeReferencingRuleTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
KnowledgePackLicense.Validate();
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
return new TestForNullArgumentBeforeReferencingRuleRule(ruleId, Id, ruleProperties);
}
public override AnticipatingMinds.CommonUIControls.PropertyPage[] GetRulePropertiesUI(IDictionary ruleProperties)
{
AnticipatingMinds.CommonUIControls.PropertyPage[] pages = new AnticipatingMinds.CommonUIControls.PropertyPage[1];
pages[0] = new TestForNullArgumentCorrectionPropertiesPage(ruleProperties);
return pages;
}
}
public class TestForNullArgumentBeforeReferencingRuleRule : Rule
{
#region Rule Property
public new class PropertyName : Rule.PropertyName
{
public const string ArgumentNullExceptionMessage = "ArgumentNullExceptionMessage";
public const string ParamNameConstructor = "ParamNameConstructor";
public const string ParamAndMessageConstructor = "ParamAndMessageConstructor";
public const string ParamAndMessageDefault = "ParamAndMessageDefault";
public const string ParamNameDefault = "ParamNameDefault";
}
private string ArgumentNullExceptionMessage
{
get{
return GetProperty(PropertyName.ArgumentNullExceptionMessage, ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|ArgumentNullExceptionMessageDefault")).ToString();
}
set{
SetProperty(PropertyName.ArgumentNullExceptionMessage, value);
}
}
private bool ParamNameConstructor
{
get{ return Convert.ToBoolean(GetProperty(PropertyName.ParamNameConstructor, true)); }
set{ SetProperty(PropertyName.ParamNameConstructor, value);}
}
private bool ParamNameDefault
{
get{ return Convert.ToBoolean(GetProperty(PropertyName.ParamNameDefault, true)); }
set{ SetProperty(PropertyName.ParamNameDefault, value);}
}
private bool ParamAndMessageConstructor
{
get{ return Convert.ToBoolean(GetProperty(PropertyName.ParamAndMessageConstructor, false)); }
set{ SetProperty(PropertyName.ParamAndMessageConstructor, value);}
}
private bool ParamAndMessageDefault
{
get{ return Convert.ToBoolean(GetProperty(PropertyName.ParamAndMessageDefault, false)); }
set{ SetProperty(PropertyName.ParamAndMessageDefault, value);}
}
#endregion
#region Rule Data
private class RuleData
{
/// <summary>
/// MethodParameters - for MethodParameter which testing now
/// </summary>
public Stack MethodParameters = new Stack();
public RuleViolationCollection violations = new RuleViolationCollection();
public string MemberName = "";
}
private class MethodParameter
{
/// <summary>
/// list object where testing current MethodParameter
/// </summary>
public ArrayList TrowArgumentNullExceptionTrace;
public CodeMethodParameter CodeMethodParameter;
public bool IsToTrowArgumentNullException;
public MethodParameter(CodeMethodParameter codeMethodParameter)
{
CodeMethodParameter = codeMethodParameter;
IsToTrowArgumentNullException = false;
TrowArgumentNullExceptionTrace = new ArrayList();
}
}
/// <summary>
///
/// </summary>
private class VariableDeclarationStatement
{
public bool IsExistsMethodParameterReferenceExpression;
public CodeMethodParameterReferenceExpression MethodParameterReferenceExpression;
public VariableDeclarationStatement(CodeMethodParameterReferenceExpression methodParameterReferenceExpression)
{
this.MethodParameterReferenceExpression = methodParameterReferenceExpression;
IsExistsMethodParameterReferenceExpression = false;
}
}
#endregion
internal TestForNullArgumentBeforeReferencingRuleRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
public override Type[] TargetedCodeElements
{
get
{
return targetedCodeElements;
}
}
#region Analyze
private RuleViolation[] AnalyzeMethod(CodeTypeMethodDeclaration methodDeclaration, RuleData ruleData)
{
string[] methodSignatureParameters = new string[methodDeclaration.Parameters.Count];
int index = 0;
string methodSignature = CodeTypeReferenceUtils.GetShortestTypeNameReference( methodDeclaration.DeclaringType, methodDeclaration.DeclaringType.FullName) + ((methodDeclaration.Name == ".ctor") ? "" : "." + methodDeclaration.Name ) +"(";
foreach(CodeMethodParameter parameter in methodDeclaration.Parameters)
{
if(CheckConfigurationData(parameter))
{
/*
* Search block where current parameter test for Null and
* exception thrown or initialize
* */
MethodParameter ruleParameter = new MethodParameter(parameter);
ruleData.MethodParameters.Push(ruleParameter);
CodeDomWalker.WalkCodeElement(methodDeclaration.Statements ,new CodeDomWalker.WalkerCallback(FindThrowArgumentNullException), ruleData);
}
string parameterModifier = "";
if(parameter.Modifier == CodeMethodParameter.CodeMethodParameterModifier.Out)
{
parameterModifier = "out";
}
else if(parameter.Modifier == CodeMethodParameter.CodeMethodParameterModifier.Ref)
{
parameterModifier = "ref";
}
methodSignatureParameters[index++] = parameterModifier +" "+ parameter.Type.TypeName +" "+ parameter.Name;
}
methodSignature += String.Join(", ", methodSignatureParameters)+ ")";
/*
* Search all CodeMethodParameterReferenceExpression in current Method
* */
CodeDomWalker.WalkCodeElement(methodDeclaration.Statements ,new CodeDomWalker.WalkerCallback(TypeMethodDeclarationAnalyzer), ruleData);
ArrayList violationMethodParameterListInMethod = new ArrayList();
for(int i = 0; i < ruleData.violations.Count ; i++)
{
RuleViolation violation = ruleData.violations[i];
CodeMethodParameterReferenceExpression parameterReference = violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
/*
* If exists several violation for parameter leave only one
* */
if(violationMethodParameterListInMethod.Contains(parameterReference.MethodParameter))
{
ruleData.violations.RemoveAt(ruleData.violations.IndexOf(violation));
i--;
continue;
}
else
{
violationMethodParameterListInMethod.Add(parameterReference.MethodParameter);
}
RuleViolationCorrection violationCorrection;
violation.ViolationData["TypeMethodDeclaration"] = methodDeclaration;
violation.ViolationData["TypeMethodDeclarationSignature"] = methodSignature;
if(this.ParamAndMessageConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamNameAndMessage"), this.ParamAndMessageDefault , false);
}
if(this.ParamNameConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamName"), this.ParamNameDefault , false);
}
}
if(ruleData.violations.Count != 0)
return ruleData.violations.ToArray();
else
return emptyViolationsList;
}
private RuleViolation[] AnalyzeIndexer(CodeTypeIndexerDeclaration indexerDeclaration, RuleData ruleData)
{
string[] methodSignatureParameters = new string[indexerDeclaration.Parameters.Count];
int index = 0;
string methodSignature = CodeTypeReferenceUtils.GetShortestTypeNameReference(indexerDeclaration.DeclaringType, indexerDeclaration.DeclaringType.FullName) + ".this[";
foreach(CodeMethodParameter parameter in indexerDeclaration.Parameters)
{
if(CheckConfigurationData(parameter))
{
/*
* Search block where current parameter test for Null and
* exception thrown or initialize
* */
MethodParameter ruleParameter = new MethodParameter(parameter);
ruleData.MethodParameters.Push(ruleParameter);
CodeDomWalker.WalkCodeElement(indexerDeclaration.SetAccessorStatements ,new CodeDomWalker.WalkerCallback(FindThrowArgumentNullException), ruleData);
CodeDomWalker.WalkCodeElement(indexerDeclaration.GetAccessorStatements ,new CodeDomWalker.WalkerCallback(FindThrowArgumentNullException), ruleData);
}
methodSignatureParameters[index++] = parameter.Type.TypeName +" "+ parameter.Name;
}
methodSignature += String.Join(", ", methodSignatureParameters)+ "]";
/*
* Search all CodeMethodParameterReferenceExpression in current Method
* */
CodeDomWalker.WalkCodeElement(indexerDeclaration.SetAccessorStatements ,new CodeDomWalker.WalkerCallback(TypeMethodDeclarationAnalyzer), ruleData);
CodeDomWalker.WalkCodeElement(indexerDeclaration.GetAccessorStatements ,new CodeDomWalker.WalkerCallback(TypeMethodDeclarationAnalyzer), ruleData);
ArrayList violationMethodParameterListInIndexerGet = new ArrayList();
ArrayList violationMethodParameterListInIndexerSet = new ArrayList();
for(int i = 0; i < ruleData.violations.Count ; i++)
{
RuleViolation violation = ruleData.violations[i];
CodeMethodParameterReferenceExpression parameterReference = violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
/*
* If exists several violation for parameter leave only one
* */
string indexerBlock = violation.ViolationData["IndexerBlockStatement"] as string;
if(indexerBlock == "GET")
{
if(violationMethodParameterListInIndexerGet.Contains(parameterReference.MethodParameter))
{
ruleData.violations.RemoveAt(ruleData.violations.IndexOf(violation));
i--;
continue;
}
else
{
violationMethodParameterListInIndexerGet.Add(parameterReference.MethodParameter);
}
}
if(indexerBlock == "SET")
{
if(violationMethodParameterListInIndexerSet.Contains(parameterReference.MethodParameter))
{
ruleData.violations.RemoveAt(ruleData.violations.IndexOf(violation));
i--;
continue;
}
else
{
violationMethodParameterListInIndexerSet.Add(parameterReference.MethodParameter);
}
}
RuleViolationCorrection violationCorrection;
violation.ViolationData["TypeMethodDeclaration"] = indexerDeclaration;
violation.ViolationData["TypeMethodDeclarationSignature"] = methodSignature;
if(this.ParamAndMessageConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamNameAndMessage"), this.ParamAndMessageDefault , false);
}
if(this.ParamNameConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamName"), this.ParamNameDefault , false);
}
}
if(ruleData.violations.Count != 0)
return ruleData.violations.ToArray();
else
return emptyViolationsList;
}
private RuleViolation[] AnalyzeProperty(CodeTypePropertyDeclaration propertyDeclaration, RuleData ruleData)
{
#region Analize Type
string parameterTypeInfoFullName = "";
if(propertyDeclaration.ReturnType.TypeInfo != null)
{
parameterTypeInfoFullName = propertyDeclaration.ReturnType.TypeInfo.FullName;
}
else return emptyViolationsList;
if(propertyDeclaration.GetAssemblyTypeManager().IsTypeSubclassOf(parameterTypeInfoFullName,typeof(ValueType).FullName))
{
return emptyViolationsList;
}
#endregion
MethodParameter ruleParameter = new MethodParameter(null);
ruleData.MethodParameters.Push(ruleParameter);
CodeDomWalker.WalkCodeElement(propertyDeclaration.SetAccessorStatements ,new CodeDomWalker.WalkerCallback(FindThrowArgumentNullExceptionUnresolvedReference), ruleData);
/*
* Search all CodeMethodParameterReferenceExpression in current Property
* */
CodeDomWalker.WalkCodeElement(propertyDeclaration.SetAccessorStatements ,new CodeDomWalker.WalkerCallback(CodeTypePropertyDeclarationAnalyzer), ruleData);
if(ruleData.violations.Count != 0)
{
RuleViolation violation = ruleData.violations[0];
RuleViolationCorrection violationCorrection;
violation.ViolationData["TypeMethodDeclaration"] = propertyDeclaration;
string methodSignature = "";
if(propertyDeclaration is CodeTypeIndexerDeclaration)
{
CodeTypeIndexerDeclaration indexerDeclaration = propertyDeclaration as CodeTypeIndexerDeclaration;
string[] methodSignatureParameters = new string[indexerDeclaration.Parameters.Count];
int index = 0;
methodSignature = CodeTypeReferenceUtils.GetShortestTypeNameReference(indexerDeclaration.DeclaringType, indexerDeclaration.DeclaringType.FullName) + ".this[";
foreach(CodeMethodParameter parameter in indexerDeclaration.Parameters)
{
methodSignatureParameters[index++] = parameter.Type.TypeName +" "+ parameter.Name;
}
methodSignature += String.Join(", ", methodSignatureParameters)+ "]";
}
else
{
methodSignature = propertyDeclaration.DeclaringType.FullName+"."+propertyDeclaration.Name;
}
violation.ViolationData["TypeMethodDeclarationSignature"] = methodSignature;
if(this.ParamAndMessageConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamNameAndMessage"), this.ParamAndMessageDefault , false);
}
if(this.ParamNameConstructor || violation.Corrections.Count == 0)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamName"), this.ParamNameDefault , false);
}
return ruleData.violations.ToArray();
}
else
return emptyViolationsList;
}
private RuleViolation[] AnalyzeEvent(CodeTypeEventDeclaration eventDeclaration, RuleData ruleData)
{
MethodParameter ruleParameter = new MethodParameter(null);
ruleData.MethodParameters.Push(ruleParameter);
CodeDomWalker.WalkCodeElement(eventDeclaration.RemoveAccessorStatements ,new CodeDomWalker.WalkerCallback(FindThrowArgumentNullExceptionUnresolvedReference), ruleData);
CodeDomWalker.WalkCodeElement(eventDeclaration.AddAccessorStatements ,new CodeDomWalker.WalkerCallback(FindThrowArgumentNullExceptionUnresolvedReference), ruleData);
/*
* Search all CodeMethodParameterReferenceExpression in current Property
* */
CodeDomWalker.WalkCodeElement(eventDeclaration.RemoveAccessorStatements ,new CodeDomWalker.WalkerCallback(CodeTypePropertyDeclarationAnalyzer), ruleData);
CodeDomWalker.WalkCodeElement(eventDeclaration.AddAccessorStatements ,new CodeDomWalker.WalkerCallback(CodeTypePropertyDeclarationAnalyzer), ruleData);
bool addAccessorBlock = false;
bool removeAccessorBlock = false;
for(int i = 0; i < ruleData.violations.Count ; i++)
{
RuleViolation violation = ruleData.violations[i];
string indexerBlock = violation.ViolationData["IndexerBlockStatement"] as string;
if(indexerBlock == "ADD")
{
if(addAccessorBlock)
{
ruleData.violations.RemoveAt(ruleData.violations.IndexOf(violation));
i--;
continue;
}
else
{
addAccessorBlock = true;
}
}
if(indexerBlock == "REMOVE")
{
if(removeAccessorBlock)
{
ruleData.violations.RemoveAt(ruleData.violations.IndexOf(violation));
i--;
continue;
}
else
{
removeAccessorBlock = true;
}
}
RuleViolationCorrection violationCorrection;
violation.ViolationData["TypeMethodDeclaration"] = eventDeclaration;
violation.ViolationData["TypeMethodDeclarationSignature"] = eventDeclaration.DeclaringType.FullName+"."+eventDeclaration.Name;
if(this.ParamAndMessageConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamNameAndMessage"), this.ParamAndMessageDefault , false);
}
if(this.ParamNameConstructor)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamName"), this.ParamNameDefault , false);
}
}
if(ruleData.violations.Count != 0)
{
return ruleData.violations.ToArray();
}
else
return emptyViolationsList;
}
public override RuleViolation[] Analyze(object codeElement, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
// Serge, I commented lines bellow because we are using applicability scope for figuring
// out which methods to analze and which one to leave alone
if(!IsCodeElementInRuleApplicabilityScope(codeElement as CodeElement))
return emptyViolationsList;
CodeTypeMethodDeclaration methodDeclaration = codeElement as CodeTypeMethodDeclaration;
CodeTypeIndexerDeclaration indexerDeclaration = codeElement as CodeTypeIndexerDeclaration;
RuleData ruleData = new RuleData();
if(methodDeclaration != null)
{
ruleData.MemberName = (methodDeclaration.Name == ".ctor") ? CodeTypeReferenceUtils.GetShortestTypeNameReference(methodDeclaration.DeclaringType, methodDeclaration.DeclaringType.FullName) + "." + methodDeclaration.DeclaringType.Name : CodeTypeReferenceUtils.GetShortestTypeNameReference(methodDeclaration.DeclaringType, methodDeclaration.DeclaringType.FullName) + "." + methodDeclaration.Name ;
return AnalyzeMethod(methodDeclaration, ruleData);
}
else if(indexerDeclaration != null)
{
ruleData.MemberName = CodeTypeReferenceUtils.GetShortestTypeNameReference(indexerDeclaration.DeclaringType, indexerDeclaration.DeclaringType.FullName)+".this";
RuleViolationCollection indexerViolation = new RuleViolationCollection();
indexerViolation.AddRange(AnalyzeIndexer(indexerDeclaration, ruleData));
return indexerViolation.ToArray();
}
else if(codeElement is CodeTypePropertyDeclaration)
{
CodeTypePropertyDeclaration propertyDeclaration = codeElement as CodeTypePropertyDeclaration;
ruleData.MemberName = CodeTypeReferenceUtils.GetShortestTypeNameReference(propertyDeclaration.DeclaringType, propertyDeclaration.DeclaringType.FullName) + "." + propertyDeclaration.Name;
return AnalyzeProperty(propertyDeclaration, ruleData);
}
else if(codeElement is CodeTypeEventDeclaration)
{
CodeTypeEventDeclaration eventDeclaration = codeElement as CodeTypeEventDeclaration;
ruleData.MemberName = CodeTypeReferenceUtils.GetShortestTypeNameReference(eventDeclaration.DeclaringType, eventDeclaration.DeclaringType.FullName)+ "." + eventDeclaration.Name;
return AnalyzeEvent(eventDeclaration, ruleData);
}
else
{
return emptyViolationsList;
}
}
private CodeDomWalker.WalkerCallbackReturn FindThrowArgumentNullExceptionUnresolvedReference(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
CodeIfStatement codeIfStatement = codeElement as CodeIfStatement;
if(codeIfStatement != null )
{
CodeExpression expression = codeIfStatement.Condition;
if(expression is CodeParenthesizedExpression)
{
expression =(expression as CodeParenthesizedExpression).Expression;
}
if(expression is CodeBinaryExpression)
{
RuleData ruleData = applicationData as RuleData;
MethodParameter ruleParameter = ruleData.MethodParameters.Peek() as MethodParameter;
if(TrowArgumentNullExceptionUnresolvedReference((CodeBinaryExpression)expression))
{
ruleParameter.TrowArgumentNullExceptionTrace.Add(codeElement);
}
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private bool CheckConfigurationData(CodeMethodParameter parameter)
{
// test parameter for simple type : if simple type (int, bool, ...) skip current parameter
string parameterTypeInfoFullName = "";
if(parameter.Type.TypeInfo != null)
{
parameterTypeInfoFullName = parameter.Type.TypeInfo.FullName;
}
else
{
return false;
}
if(parameter.GetAssemblyTypeManager().IsTypeSubclassOf(parameterTypeInfoFullName,typeof(ValueType).FullName))
{
return false;
}
/// if parameter is Array
if(parameter.IsParameterArray)
{
return false;
}
// test for Modifier : if ref/out skip current parameter
if(parameter.Modifier == CodeMethodParameter.CodeMethodParameterModifier.Out || parameter.Modifier == CodeMethodParameter.CodeMethodParameterModifier.Ref)
{
return false;
}
return true;
}
private CodeDomWalker.WalkerCallbackReturn FindThrowArgumentNullException(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
CodeIfStatement codeIfStatement = codeElement as CodeIfStatement;
if(codeIfStatement != null )
{
CodeExpression expression = codeIfStatement.Condition;
if(expression is CodeParenthesizedExpression)
{
expression =(expression as CodeParenthesizedExpression).Expression;
}
if(expression is CodeBinaryExpression)
{
RuleData ruleData = applicationData as RuleData;
MethodParameter ruleParameter = ruleData.MethodParameters.Peek() as MethodParameter;
CodeMethodParameter codeMethodParameter = TrowArgumentNullException((CodeBinaryExpression)expression);
if(codeMethodParameter == ruleParameter.CodeMethodParameter)
{
ruleParameter.TrowArgumentNullExceptionTrace.Add(codeElement);
}
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private CodeDomWalker.WalkerCallbackReturn CodeTypePropertyDeclarationAnalyzer(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
CodeMethodParameterReferenceExpression unresolvedReference = codeElement as CodeMethodParameterReferenceExpression;
RuleData ruleData = applicationData as RuleData;
if(unresolvedReference != null && notificationType == CodeDomWalker.CallBackNotificationType.OnElement )
{
#region create list with code elements
ArrayList listElement = new ArrayList();
System.Collections.IEnumerator ruleDataEnumerator = ruleData.MethodParameters.GetEnumerator();
while( ruleDataEnumerator.MoveNext() )
{
MethodParameter mParameter = ruleDataEnumerator.Current as MethodParameter;
if( mParameter.CodeMethodParameter == null )
{
listElement = mParameter.TrowArgumentNullExceptionTrace;
}
}
#endregion
if(unresolvedReference.Parent is CodeBinaryExpression
&& ((unresolvedReference.Parent as CodeBinaryExpression).Operator == CodeBinaryOperatorType.Equality || (unresolvedReference.Parent as CodeBinaryExpression).Operator == CodeBinaryOperatorType.Inequality)
)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
#region Check if parameter is compared to null. If yes - clear violations and exit. Developers thought of this case
CodeExpression parameterReferenceExpression = unresolvedReference;
//Skip parethethies
while(parameterReferenceExpression.Parent is CodeParenthesizedExpression)
parameterReferenceExpression = parameterReferenceExpression.Parent as CodeExpression;
//Check if inside comparison
//If the condition has comparison to null - return there. After that point developer
//evidently thought of case where parameter is null.
if(parameterReferenceExpression.Parent is CodeBinaryExpression)
{
CodeBinaryExpression binaryExpression = parameterReferenceExpression.Parent as CodeBinaryExpression;
if(binaryExpression.Operator == CodeBinaryOperatorType.Equality
|| binaryExpression.Operator == CodeBinaryOperatorType.Inequality)
{
if(binaryExpression.RightOperand is CodeNullReferenceExpression || binaryExpression.LeftOperand is CodeNullReferenceExpression)
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
}
#endregion
CodeElementTrace trace = CodeElementTrace.GetCodeElementTrace(codeElement);
string indexerBlockStatement = "";
for(int traceFrameIndex = trace.Trace.Length-1;traceFrameIndex>=0; traceFrameIndex--)
{
#region CodeIfStatement Analize
// if exists testing for null in parent elements
if(trace.Trace[traceFrameIndex] is CodeIfStatement )
{
CodeIfStatement ifStatement = trace.Trace[traceFrameIndex] as CodeIfStatement;
CodeStatement statement = trace.Trace[traceFrameIndex + 1] as CodeStatement;
if(statement == null) continue;
if(CheckExpression(ifStatement.Condition, unresolvedReference, statement.Equals(ifStatement.TrueStatement)))
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
#endregion
#region CodeConditionalExpression Analize
if(trace.Trace[traceFrameIndex] is CodeConditionalExpression )
{
CodeConditionalExpression conditionalExpression = trace.Trace[traceFrameIndex] as CodeConditionalExpression;
CodeExpression expression = conditionalExpression.Condition;
if(expression is CodeParenthesizedExpression)
{
expression = (expression as CodeParenthesizedExpression).Expression;
}
if(expression is CodeBinaryExpression)
{
CodeExpression codeExpression = trace.Trace[traceFrameIndex + 1] as CodeExpression;
if(CheckCodeBinaryExpressionUnresolvedReference(unresolvedReference, (CodeBinaryExpression)expression, codeExpression.Equals(conditionalExpression.TrueExpression)))
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
}
#endregion
#region CodeTryStatement Analize
if(trace.Trace[traceFrameIndex] is CodeTryStatement && trace.Trace[traceFrameIndex + 1] is CodeStatementBlock)
{
CodeTryStatement tryStatement = trace.Trace[traceFrameIndex] as CodeTryStatement;
foreach(CodeCatchClause catchClause in tryStatement.CatchClauses)
{
CodeAssemblyTypeManager typeManager = tryStatement.GetAssemblyTypeManager();
if(catchClause.CatchExceptionType != null && catchClause.CatchExceptionType.TypeInfo != null)
{
if( typeManager.IsTypeSubclassOf(catchClause.CatchExceptionType.TypeInfo.FullName, "System.ArgumentNullException") )
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
}
}
#endregion
#region CodeStatementBlock Analize
if(trace.Trace[traceFrameIndex] is CodeStatementBlock)
{
foreach(CodeElement traceElement in (trace.Trace[traceFrameIndex] as CodeStatementBlock).Statements )
{
if(listElement.Contains(traceElement))
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
if(trace.Trace[traceFrameIndex+1] == traceElement)
break;
}
}
#endregion
if(trace.Trace[traceFrameIndex] is CodeTypeMethodDeclaration)
break;
if(trace.Trace[traceFrameIndex] is CodeTypeIndexerDeclaration )
{
indexerBlockStatement = (trace.Trace[traceFrameIndex+1] == (trace.Trace[traceFrameIndex] as CodeTypeIndexerDeclaration).SetAccessorStatements)?"SET":"GET";
break;
}
if(trace.Trace[traceFrameIndex] is CodeTypePropertyDeclaration)
{
indexerBlockStatement = (trace.Trace[traceFrameIndex+1] == (trace.Trace[traceFrameIndex] as CodeTypePropertyDeclaration).SetAccessorStatements)?"SET":"GET";
break;
}
if(trace.Trace[traceFrameIndex] is CodeTypeEventDeclaration)
{
indexerBlockStatement = (trace.Trace[traceFrameIndex+1] == (trace.Trace[traceFrameIndex] as CodeTypeEventDeclaration).AddAccessorStatements)?"ADD":"REMOVE";
break;
}
}
if(!isParameterUsedAsTargetInReference(unresolvedReference))
{return CodeDomWalker.WalkerCallbackReturn.Next;}
RuleViolation violation = new RuleViolation(this, unresolvedReference);
violation.Description = String.Format(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|Description"), "value", ruleData.MemberName);
violation.Severity = RuleViolation.ViolationSeverity.Warning;
violation.ViolationData["MethodParameterReferenceExpression"] = unresolvedReference;
violation.ViolationData["IndexerBlockStatement"] = indexerBlockStatement;
ruleData.violations.Add(violation);
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private bool AnalizeBinaryExcpression(CodeBinaryExpression binary, CodeMethodParameterReferenceExpression parameterReference)
{
if(binary.RightOperand == parameterReference
&& binary.Operator == CodeBinaryOperatorType.Assign)
return true;
return false;
}
private CodeDomWalker.WalkerCallbackReturn TypeMethodDeclarationAnalyzer(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
CodeMethodParameterReferenceExpression parameterReference = codeElement as CodeMethodParameterReferenceExpression;
RuleData ruleData = applicationData as RuleData;
if(parameterReference != null && parameterReference.MethodParameter != null && notificationType == CodeDomWalker.CallBackNotificationType.OnElement )
{
#region create list with code elements
ArrayList listElement = new ArrayList();
System.Collections.IEnumerator ruleDataEnumerator = ruleData.MethodParameters.GetEnumerator();
while( ruleDataEnumerator.MoveNext() )
{
MethodParameter mParameter = ruleDataEnumerator.Current as MethodParameter;
if( mParameter.CodeMethodParameter == parameterReference.MethodParameter )
{
listElement = mParameter.TrowArgumentNullExceptionTrace;
}
}
#endregion
if(!CheckConfigurationData(parameterReference.MethodParameter))
return CodeDomWalker.WalkerCallbackReturn.Next;
#region Check if parameter is compared to null. If yes - clear violations and exit. Developers thought of this case
CodeExpression parameterReferenceExpression = parameterReference;
//Skip parethethies
while(parameterReferenceExpression.Parent is CodeParenthesizedExpression)
parameterReferenceExpression = parameterReferenceExpression.Parent as CodeExpression;
//Check if inside comparison
//If the condition has comparison to null - return there. After that point developer
//evidently thought of case where parameter is null.
if(parameterReferenceExpression.Parent is CodeBinaryExpression)
{
CodeBinaryExpression binaryExpression = parameterReferenceExpression.Parent as CodeBinaryExpression;
if(binaryExpression.Operator == CodeBinaryOperatorType.Equality
|| binaryExpression.Operator == CodeBinaryOperatorType.Inequality)
{
if(binaryExpression.RightOperand is CodeNullReferenceExpression || binaryExpression.LeftOperand is CodeNullReferenceExpression)
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
}
#endregion
if(parameterReference.Parent is CodeBinaryExpression
&& ((parameterReference.Parent as CodeBinaryExpression).Operator == CodeBinaryOperatorType.Equality
|| (parameterReference.Parent as CodeBinaryExpression).Operator == CodeBinaryOperatorType.Inequality
|| (parameterReference.Parent as CodeBinaryExpression).Operator == CodeBinaryOperatorType.Is)
)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
CodeElementTrace trace = CodeElementTrace.GetCodeElementTrace(codeElement);
string indexerBlockStatement = "";
for(int traceFrameIndex = trace.Trace.Length-1;traceFrameIndex>=0; traceFrameIndex--)
{
#region CodeIfStatement Analize
if(trace.Trace[traceFrameIndex] is CodeIfStatement )
{
CodeIfStatement ifStatement = trace.Trace[traceFrameIndex] as CodeIfStatement;
CodeStatement statement = trace.Trace[traceFrameIndex + 1] as CodeStatement;
if(statement == null) continue;
if(CheckExpression(ifStatement.Condition, parameterReference, statement.Equals(ifStatement.TrueStatement)))
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
#endregion
#region CodeConditionalExpression Analize
if(trace.Trace[traceFrameIndex] is CodeConditionalExpression )
{
CodeConditionalExpression conditionalExpression = trace.Trace[traceFrameIndex] as CodeConditionalExpression;
CodeExpression expression = conditionalExpression.Condition;
if(expression is CodeParenthesizedExpression)
{
expression = (expression as CodeParenthesizedExpression).Expression;
}
if(expression is CodeBinaryExpression)
{
CodeExpression codeExpression = trace.Trace[traceFrameIndex + 1] as CodeExpression;
if(CheckCodeBinaryExpression(parameterReference, (CodeBinaryExpression)expression, codeExpression.Equals(conditionalExpression.TrueExpression)))
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
}
#endregion
#region CodeTryStatement Analize
if(trace.Trace[traceFrameIndex] is CodeTryStatement && trace.Trace[traceFrameIndex + 1] is CodeStatementBlock)
{
CodeTryStatement tryStatement = trace.Trace[traceFrameIndex] as CodeTryStatement;
foreach(CodeCatchClause catchClause in tryStatement.CatchClauses)
{
CodeAssemblyTypeManager typeManager = tryStatement.GetAssemblyTypeManager();
if(catchClause.CatchExceptionType != null && catchClause.CatchExceptionType.TypeInfo != null)
{
if( typeManager.IsTypeSubclassOf(catchClause.CatchExceptionType.TypeInfo.FullName, "System.ArgumentNullException") )
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
}
}
#endregion
#region CodeStatementBlock Analize
if(trace.Trace[traceFrameIndex] is CodeStatementBlock)
{
foreach(CodeElement traceElement in (trace.Trace[traceFrameIndex] as CodeStatementBlock).Statements )
{
if(listElement.Contains(traceElement))
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
if(trace.Trace[traceFrameIndex+1] == traceElement)
break;
}
}
#endregion
if(trace.Trace[traceFrameIndex] is CodeTypeMethodDeclaration)
break;
if(trace.Trace[traceFrameIndex] is CodeTypeIndexerDeclaration)
{
indexerBlockStatement = (trace.Trace[traceFrameIndex+1] == (trace.Trace[traceFrameIndex] as CodeTypeIndexerDeclaration).SetAccessorStatements)?"SET":"GET";
break;
}
}
if(!isParameterUsedAsTargetInReference(parameterReference))
{return CodeDomWalker.WalkerCallbackReturn.Next;}
RuleViolation violation = new RuleViolation(this, parameterReference);
violation.Description = String.Format(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|Description"), parameterReference.ParameterName, ruleData.MemberName);
violation.Severity = RuleViolation.ViolationSeverity.Warning;
violation.ViolationData["MethodParameterReferenceExpression"] = parameterReference;
violation.ViolationData["IndexerBlockStatement"] = indexerBlockStatement;
ruleData.violations.Add(violation);
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private bool isParameterUsedAsTargetInReference(CodeElement parameterReference)
{
CodeElement child = parameterReference;
//skip parenthethies and type casts
while(
child.Parent is CodeParenthesizedExpression ||
child.Parent is CodeTypeCastExpression ||
(child.Parent is CodeBinaryExpression && ((child.Parent as CodeBinaryExpression).Operator == CodeBinaryOperatorType.As)))
{
child = child.Parent;
}
if((child.Parent is CodeNamedReferenceExpression)
&& (child.Parent as CodeNamedReferenceExpression).TargetObject == child)
{
return true;
}
if(parameterReference.Parent is CodeIndexerInvokeExpression)
{
return true;
}
return false;
}
private bool CheckExpression(CodeExpression condition, CodeMethodParameterReferenceExpression parameterReference, bool trueBlock)
{
if(condition is CodeParenthesizedExpression)
{
condition = (condition as CodeParenthesizedExpression).Expression;
}
if(condition is CodeBinaryExpression)
{
CodeBinaryExpression binary = condition as CodeBinaryExpression;
CodeExpression leftOperand = binary.LeftOperand;
if(leftOperand is CodeParenthesizedExpression) leftOperand = (leftOperand as CodeParenthesizedExpression).Expression;
CodeExpression rightOperand = binary.RightOperand;
if(rightOperand is CodeParenthesizedExpression) rightOperand = (rightOperand as CodeParenthesizedExpression).Expression;
if(leftOperand is CodeBinaryExpression && rightOperand is CodeBinaryExpression)
{
if(binary.Operator == CodeBinaryOperatorType.LogicalOr)
{
return (CheckExpression(leftOperand, parameterReference, trueBlock) && CheckExpression(rightOperand, parameterReference, trueBlock));
}
if(binary.Operator == CodeBinaryOperatorType.LogicalAnd)
{
return (CheckExpression(leftOperand, parameterReference, trueBlock) || CheckExpression(rightOperand, parameterReference, trueBlock));
}
}
else
{
return CheckCodeBinaryExpression(parameterReference, binary, trueBlock);
}
}
return false;
}
#region Analize CodeIf statement for intricate variant: if(arg != null && arg.Lenght != 0) and other
private class ifStatementCondiotion
{
public CodeMethodParameterReferenceExpression ParameterReference;
public CodeBinaryOperatorType CheckType = CodeBinaryOperatorType.Inequality;
public bool TestForInEqualityNull = false;
}
private bool CheckCodeIfStatement(CodeMethodParameterReferenceExpression parameterReference, CodeIfStatement ifStatement, CodeStatement statement)
{
ifStatementCondiotion conditionData = new ifStatementCondiotion();
conditionData.ParameterReference = parameterReference;
if(statement != null)
{
conditionData.CheckType =( !statement.Equals(ifStatement.TrueStatement))?CodeBinaryOperatorType.Equality:CodeBinaryOperatorType.Inequality;
}
CodeDomWalker.WalkCodeElement(ifStatement.Condition, new CodeDomWalker.WalkerCallback(CheckIfStatementCondition), conditionData);
return conditionData.TestForInEqualityNull;
}
private CodeDomWalker.WalkerCallbackReturn CheckIfStatementCondition(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
if(codeElement is CodeBinaryExpression)
{
CodeBinaryExpression binary = codeElement as CodeBinaryExpression;
ifStatementCondiotion conditionData = applicationData as ifStatementCondiotion;
if((binary.Operator == conditionData.CheckType
&& binary.LeftOperand is CodeMethodParameterReferenceExpression
&& binary.RightOperand is CodeNullReferenceExpression)
||
(binary.Operator == conditionData.CheckType
&& binary.RightOperand is CodeMethodParameterReferenceExpression
&& binary.LeftOperand is CodeNullReferenceExpression)
)
{
if(conditionData.ParameterReference.ParameterName == (binary.LeftOperand as CodeMethodParameterReferenceExpression).ParameterName)
conditionData.TestForInEqualityNull = true;
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
#endregion
private bool CheckCodeBinaryExpression(CodeMethodParameterReferenceExpression parameterReference, CodeBinaryExpression binaryExpression, bool trueBlock)
{
bool contentsParameterReferenceAndNull = false;
if(binaryExpression.Operator == CodeBinaryOperatorType.Is
&& binaryExpression.LeftOperand is CodeMethodParameterReferenceExpression
&& binaryExpression.RightOperand is CodeTypeReferenceExpression
)
{
return trueBlock;
}
if(binaryExpression.LeftOperand is CodeMethodParameterReferenceExpression)
{
if((binaryExpression.LeftOperand as CodeMethodParameterReferenceExpression).MethodParameter == parameterReference.MethodParameter && binaryExpression.RightOperand is CodeNullReferenceExpression)
{
contentsParameterReferenceAndNull = true;
}
}
if(binaryExpression.RightOperand is CodeMethodParameterReferenceExpression)
{
if((binaryExpression.RightOperand as CodeMethodParameterReferenceExpression).MethodParameter == parameterReference.MethodParameter && binaryExpression.LeftOperand is CodeNullReferenceExpression)
{
contentsParameterReferenceAndNull = true;
}
}
if(!contentsParameterReferenceAndNull)
return false;
if( (binaryExpression.Operator == CodeBinaryOperatorType.Inequality && trueBlock)
||
(binaryExpression.Operator == CodeBinaryOperatorType.Equality && !trueBlock )
)
{
return true;
}
return false;
}
private bool CheckCodeBinaryExpressionUnresolvedReference(CodeMethodParameterReferenceExpression parameterReference, CodeBinaryExpression binaryExpression, bool trueBlock)
{
bool contentsParameterReferenceAndNull = false;
if(binaryExpression.LeftOperand is CodeMethodParameterReferenceExpression && (binaryExpression.LeftOperand as CodeMethodParameterReferenceExpression).ParameterName == "value")
{
contentsParameterReferenceAndNull = true;
}
if(binaryExpression.RightOperand is CodeMethodParameterReferenceExpression && (binaryExpression.RightOperand as CodeMethodParameterReferenceExpression).ParameterName == "value")
{
contentsParameterReferenceAndNull = true;
}
if(!contentsParameterReferenceAndNull)
return false;
if( (binaryExpression.Operator == CodeBinaryOperatorType.Inequality && trueBlock)
||
(binaryExpression.Operator == CodeBinaryOperatorType.Equality && !trueBlock )
)
{
return true;
}
return false;
}
private bool CheckCodeBinaryExceptionAssign(CodeMethodParameter parameter, CodeBinaryExpression binaryExpression)
{
// testing on initialize current parameter
if(binaryExpression.Operator == CodeBinaryOperatorType.Assign)
{
if(binaryExpression.LeftOperand is CodeMethodParameterReferenceExpression
&&
(binaryExpression.LeftOperand as CodeMethodParameterReferenceExpression).MethodParameter == parameter
)
{
return true;
}
}
return false;
}
private bool TrowArgumentNullExceptionUnresolvedReference(CodeBinaryExpression binaryExpression)
{
#region find UnresolvedReferenceAndNull
bool contentsParameterReferenceAndNull = false;
if(binaryExpression.LeftOperand is CodeMethodParameterReferenceExpression && (binaryExpression.LeftOperand as CodeMethodParameterReferenceExpression).ParameterName == "value" && binaryExpression.RightOperand is CodeNullReferenceExpression)
{
contentsParameterReferenceAndNull = true;
}
if(binaryExpression.RightOperand is CodeMethodParameterReferenceExpression && (binaryExpression.RightOperand as CodeMethodParameterReferenceExpression).ParameterName == "value" && binaryExpression.LeftOperand is CodeNullReferenceExpression)
{
contentsParameterReferenceAndNull = true;
}
if(!contentsParameterReferenceAndNull)
return false;
#endregion
MethodParameter ifStatementData = new MethodParameter(null);
CodeIfStatement codeIfStatement;
if(binaryExpression.Parent is CodeParenthesizedExpression)
{
codeIfStatement = binaryExpression.Parent.Parent as CodeIfStatement;
}
else
{
codeIfStatement = binaryExpression.Parent as CodeIfStatement;
}
if( binaryExpression.Operator == CodeBinaryOperatorType.Equality )
{
CodeDomWalker.WalkCodeElement( codeIfStatement.TrueStatement ,new CodeDomWalker.WalkerCallback(CodeIfStatementAnalyzer), ifStatementData);
}
else
{
CodeDomWalker.WalkCodeElement( codeIfStatement.FalseStatement ,new CodeDomWalker.WalkerCallback(CodeIfStatementAnalyzer), ifStatementData);
}
return ifStatementData.IsToTrowArgumentNullException;
}
private CodeMethodParameter TrowArgumentNullException(CodeBinaryExpression binaryExpression)
{
#region find ParameterReferenceAndNull
bool contentsParameterReferenceAndNull = false;
CodeMethodParameter methodParameter = null;
if(binaryExpression.LeftOperand is CodeMethodParameterReferenceExpression && binaryExpression.RightOperand is CodeNullReferenceExpression)
{
methodParameter = (binaryExpression.LeftOperand as CodeMethodParameterReferenceExpression).MethodParameter;
contentsParameterReferenceAndNull = true;
}
if(binaryExpression.RightOperand is CodeMethodParameterReferenceExpression && binaryExpression.LeftOperand is CodeNullReferenceExpression)
{
methodParameter = (binaryExpression.RightOperand as CodeMethodParameterReferenceExpression).MethodParameter;
contentsParameterReferenceAndNull = true;
}
if(!contentsParameterReferenceAndNull)
return null;
#endregion
MethodParameter ifStatementData = new MethodParameter(methodParameter);
CodeIfStatement codeIfStatement;
if(binaryExpression.Parent is CodeParenthesizedExpression)
{
codeIfStatement = binaryExpression.Parent.Parent as CodeIfStatement;
}
else
{
codeIfStatement = binaryExpression.Parent as CodeIfStatement;
}
if( binaryExpression.Operator == CodeBinaryOperatorType.Equality )
{
CodeDomWalker.WalkCodeElement( codeIfStatement.TrueStatement ,new CodeDomWalker.WalkerCallback(CodeIfStatementAnalyzer), ifStatementData);
}
else
{
CodeDomWalker.WalkCodeElement( codeIfStatement.FalseStatement ,new CodeDomWalker.WalkerCallback(CodeIfStatementAnalyzer), ifStatementData);
}
return (ifStatementData.IsToTrowArgumentNullException)? methodParameter : null;
}
private CodeDomWalker.WalkerCallbackReturn CodeIfStatementAnalyzer(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
return CodeDomWalker.WalkerCallbackReturn.Next;
MethodParameter ifSatementData = applicationData as MethodParameter;
if(codeElement is CodeMethodParameterReferenceExpression && (codeElement as CodeMethodParameterReferenceExpression).MethodParameter == ifSatementData.CodeMethodParameter)
{
// testing on initialize current MethodParameter
if(codeElement.Parent is CodeBinaryExpression )
{
if(CheckCodeBinaryExceptionAssign( ifSatementData.CodeMethodParameter, (CodeBinaryExpression)codeElement.Parent))
{
ifSatementData.IsToTrowArgumentNullException = true;
}
}
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
if(codeElement is CodeThrowStatement)
{
// testing on throwing ArgumentNullException
CodeObjectCreateExpression objectCreateExpression;
if((codeElement as CodeThrowStatement).ToThrow is CodeParenthesizedExpression )
{
objectCreateExpression = ((codeElement as CodeThrowStatement).ToThrow as CodeParenthesizedExpression).Expression as CodeObjectCreateExpression;
}
else
{
objectCreateExpression = (codeElement as CodeThrowStatement).ToThrow as CodeObjectCreateExpression;
}
if(objectCreateExpression != null)
{
CodeAssemblyTypeManager typeManager = objectCreateExpression.GetAssemblyTypeManager();
if(objectCreateExpression.CreateType.TypeInfo != null)
{
if(typeManager.IsTypeSubclassOf(objectCreateExpression.CreateType.TypeInfo.FullName, "System.ArgumentNullException"))
{
ifSatementData.IsToTrowArgumentNullException = true;
}
}
}
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
#endregion
#region Correct
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
codeEffector.BeginCodeChanges("And If Statement");
foreach(RuleViolationCorrection requestedCorrection in requestedCorrections)
{
if(requestedCorrection.Violation.IsFixed)
continue;
CodeStatementCollection ifStatementCollection = new CodeStatementCollection();
bool isParamNameAndMessageDefault = requestedCorrection.Name.Equals(ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|Violation|ParamNameAndMessage"));
string methodSignature = requestedCorrection.Violation.ViolationData["TypeMethodDeclarationSignature"] as string;
CodeReferenceExpression methodExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeReferenceExpression;
string parameterName;
if(requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] is CodeMethodParameterReferenceExpression)
{
parameterName = (requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression).ParameterName;
}
else
{
parameterName = "value";
}
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeIfStatement codeIfStatement = CreateCodeIfStatement(methodExpression, isParamNameAndMessageDefault, methodSignature, parameterName);
ifStatementCollection.Add(codeIfStatement);
if(requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] is CodeTypeMethodDeclaration)
{
CorrectMethod(requestedCorrection, codeEffector, ifStatementCollection);
}
else if(requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] is CodeTypeIndexerDeclaration)
{
string indexerBlock = requestedCorrection.Violation.ViolationData["IndexerBlockStatement"] as string;
if(indexerBlock == "GET")
CorrectIndexerGet(requestedCorrection, codeEffector, ifStatementCollection);
if(indexerBlock == "SET")
CorrectIndexerSet(requestedCorrection, codeEffector, ifStatementCollection);
}
else if(requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] is CodeTypeEventDeclaration)
{
string indexerBlock = requestedCorrection.Violation.ViolationData["IndexerBlockStatement"] as string;
if(indexerBlock == "ADD")
CorrectEventAdd(requestedCorrection, codeEffector, ifStatementCollection);
if(indexerBlock == "REMOVE")
CorrectEventRemove(requestedCorrection, codeEffector, ifStatementCollection);
}
else if(requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] is CodeTypePropertyDeclaration)
{
CorrectProperty(requestedCorrection, codeEffector, ifStatementCollection);
}
requestedCorrection.Violation.IsFixed = true;
}
try
{
codeEffector.CommitCodeChanges();
}
catch(Exception)
{
codeEffector.RollbackCodeChanges();
throw;
}
}
private void CorrectIndexerSet(RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, CodeStatementCollection ifStatementCollection)
{
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeTypeIndexerDeclaration indexerDeclaration = requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] as CodeTypeIndexerDeclaration;
//Always insert at the start of the method
codeEffector.AddCodeElements( ifStatementCollection, indexerDeclaration.SetAccessorStatements, indexerDeclaration.SetAccessorStatements.Statements, 0);
codeEffector.PerformCodeChanges();
}
private void CorrectIndexerGet(RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, CodeStatementCollection ifStatementCollection)
{
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeTypeIndexerDeclaration indexerDeclaration = requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] as CodeTypeIndexerDeclaration;
//Always insert at the start of the method
codeEffector.AddCodeElements( ifStatementCollection, indexerDeclaration.GetAccessorStatements, indexerDeclaration.GetAccessorStatements.Statements, 0);
codeEffector.PerformCodeChanges();
}
private void CorrectProperty(RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, CodeStatementCollection ifStatementCollection)
{
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeTypePropertyDeclaration propertyDeclaration = requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] as CodeTypePropertyDeclaration;
//Always insert at the start of the method
codeEffector.AddCodeElements( ifStatementCollection, propertyDeclaration.SetAccessorStatements, propertyDeclaration.SetAccessorStatements.Statements, 0);
codeEffector.PerformCodeChanges();
}
private void CorrectEventAdd(RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, CodeStatementCollection ifStatementCollection)
{
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeTypeEventDeclaration eventDeclaration = requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] as CodeTypeEventDeclaration;
//Always insert at the start of the method
codeEffector.AddCodeElements( ifStatementCollection, eventDeclaration.AddAccessorStatements, eventDeclaration.AddAccessorStatements.Statements, 0);
codeEffector.PerformCodeChanges();
}
private void CorrectEventRemove(RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, CodeStatementCollection ifStatementCollection)
{
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeTypeEventDeclaration eventDeclaration = requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] as CodeTypeEventDeclaration;
//Always insert at the start of the method
codeEffector.AddCodeElements( ifStatementCollection, eventDeclaration.RemoveAccessorStatements, eventDeclaration.RemoveAccessorStatements.Statements, 0);
codeEffector.PerformCodeChanges();
}
private void CorrectMethod(RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, CodeStatementCollection ifStatementCollection)
{
CodeMethodParameterReferenceExpression methodParameterExpression = requestedCorrection.Violation.ViolationData["MethodParameterReferenceExpression"] as CodeMethodParameterReferenceExpression;
CodeTypeMethodDeclaration methodDeclaration = requestedCorrection.Violation.ViolationData["TypeMethodDeclaration"] as CodeTypeMethodDeclaration;
//Always insert at the start of the method
codeEffector.AddCodeElements( ifStatementCollection, methodDeclaration.Statements, methodDeclaration.Statements.Statements, 0);
codeEffector.PerformCodeChanges();
}
private AnticipatingMinds.Genesis.CodeDOM.CodeDomWalker.WalkerCallbackReturn FindVariableDeclarationStatement(CodeElement codeElement,AnticipatingMinds.Genesis.CodeDOM.CodeDomWalker.CallBackNotificationType notificationType, AnticipatingMinds.Genesis.CodeDOM.CodeDomWalkerContext walkerContext,object applicationData)
{
// search current MethodParameterReferenceExpression in CodeVariableDeclarationStatement
if(notificationType == CodeDomWalker.CallBackNotificationType.OnElement)
{
VariableDeclarationStatement variableDeclarationStatementData = applicationData as VariableDeclarationStatement;
if(variableDeclarationStatementData.MethodParameterReferenceExpression == codeElement)
{
variableDeclarationStatementData.IsExistsMethodParameterReferenceExpression = true;
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private CodeIfStatement CreateCodeIfStatement(CodeReferenceExpression methodParameterExpression, bool isParamNameAndMessageDefault, string methodSignature, string parameterName)
{
#region Create BinaryExpression Equality
CodeBinaryExpression binaryExpression = new CodeBinaryExpression();
binaryExpression.Operator = CodeBinaryOperatorType.Equality;
binaryExpression.LeftOperand = methodParameterExpression.Clone() as CodeExpression;
binaryExpression.RightOperand = new CodeNullReferenceExpression();
#endregion
#region Create TrueStatement
CodeObjectCreateExpression objectCreateExpression = new CodeObjectCreateExpression();
objectCreateExpression.CreateType = new CodeTypeReference("System.ArgumentNullException");
CodePrimitiveExpression primitiveExpression = new CodePrimitiveExpression(parameterName);
CodeArgument paramNameArgument = new CodeArgument();
paramNameArgument.Value = primitiveExpression;
objectCreateExpression.Arguments.Add(paramNameArgument);
if(isParamNameAndMessageDefault){
string ErrorMessage;
try
{
String.Format(this.ArgumentNullExceptionMessage, parameterName, methodSignature);
ErrorMessage = this.ArgumentNullExceptionMessage;
}
catch(System.FormatException)
{
ErrorMessage = ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|ArgumentNullExceptionMessageDefault");
}
CodePrimitiveExpression primitiveExpressionMessage = new CodePrimitiveExpression(ErrorMessage);
CodeArgument paramStringMessageArgument = new CodeArgument();
paramStringMessageArgument.Value = primitiveExpressionMessage;
CodePrimitiveExpression primitiveExpressionParameterName = new CodePrimitiveExpression(parameterName);
CodeArgument paramStringParameterNameArgument = new CodeArgument();
paramStringParameterNameArgument.Value = primitiveExpressionParameterName;
CodePrimitiveExpression primitiveExpressionMethodSignature = new CodePrimitiveExpression(methodSignature);
CodeArgument paramMethodNameArgument = new CodeArgument();
paramMethodNameArgument.Value = primitiveExpressionMethodSignature;
CodeTypeReference stringTypeReference = new CodeTypeReference("String");
CodeTypeReferenceExpression stringTypeReferenceExpresion = new CodeTypeReferenceExpression(stringTypeReference);
CodeMethodInvokeExpression methodInfokeExpression = new CodeMethodInvokeExpression();
methodInfokeExpression.Arguments.Add(paramStringMessageArgument);
methodInfokeExpression.Arguments.Add(paramStringParameterNameArgument);
methodInfokeExpression.Arguments.Add(paramMethodNameArgument);
methodInfokeExpression.MethodReferenceExpression = new CodeMethodReferenceExpression(stringTypeReferenceExpresion, "Format");
CodeArgument paramMessageArgument = new CodeArgument();
paramMessageArgument.Value = methodInfokeExpression;
objectCreateExpression.Arguments.Add(paramMessageArgument);
}
CodeParenthesizedExpression codeParenthesizedExpression = new CodeParenthesizedExpression();
codeParenthesizedExpression.Expression = objectCreateExpression;
CodeThrowStatement throwStatement = new CodeThrowStatement();
throwStatement.ToThrow = codeParenthesizedExpression;
CodeStatementBlock codeStatementThrowBlock = new CodeStatementBlock();
codeStatementThrowBlock.Statements.Add(throwStatement);
#endregion
CodeIfStatement ifStatement = new CodeIfStatement();
ifStatement.Condition = binaryExpression;
ifStatement.TrueStatement = codeStatementThrowBlock;
return ifStatement;
}
private CodeIfStatement CreateCodeIfStatementUnresolvedReference(CodeMethodParameterReferenceExpression methodParameterExpression, bool isParamNameAndMessageDefault, string methodSignature)
{
#region Create BinaryExpression Equality
CodeBinaryExpression binaryExpression = new CodeBinaryExpression();
binaryExpression.Operator = CodeBinaryOperatorType.Equality;
binaryExpression.LeftOperand = methodParameterExpression.Clone() as CodeExpression;
binaryExpression.RightOperand = new CodeNullReferenceExpression();
#endregion
#region Create TrueStatement
CodeObjectCreateExpression objectCreateExpression = new CodeObjectCreateExpression();
objectCreateExpression.CreateType = new CodeTypeReference("System.ArgumentNullException");
CodePrimitiveExpression primitiveExpression = new CodePrimitiveExpression(methodParameterExpression.ParameterName);
CodeArgument paramNameArgument = new CodeArgument();
paramNameArgument.Value = primitiveExpression;
objectCreateExpression.Arguments.Add(paramNameArgument);
if(isParamNameAndMessageDefault)
{
string ErrorMessage;
try
{
String.Format(this.ArgumentNullExceptionMessage, methodParameterExpression.ParameterName, methodSignature);
ErrorMessage = this.ArgumentNullExceptionMessage;
}
catch(System.FormatException)
{
ErrorMessage = ResourceManager.GetLocalizedString("TestForNullArgumentBeforeReferencingRuleTemplate|ArgumentNullExceptionMessageDefault");
}
CodePrimitiveExpression primitiveExpressionMessage = new CodePrimitiveExpression(ErrorMessage);
CodeArgument paramStringMessageArgument = new CodeArgument();
paramStringMessageArgument.Value = primitiveExpressionMessage;
CodePrimitiveExpression primitiveExpressionParameterName = new CodePrimitiveExpression(methodParameterExpression.ParameterName);
CodeArgument paramStringParameterNameArgument = new CodeArgument();
paramStringParameterNameArgument.Value = primitiveExpressionParameterName;
CodePrimitiveExpression primitiveExpressionMethodSignature = new CodePrimitiveExpression(methodSignature);
CodeArgument paramMethodNameArgument = new CodeArgument();
paramMethodNameArgument.Value = primitiveExpressionMethodSignature;
CodeTypeReference stringTypeReference = new CodeTypeReference("String");
CodeTypeReferenceExpression stringTypeReferenceExpresion = new CodeTypeReferenceExpression(stringTypeReference);
CodeMethodInvokeExpression methodInfokeExpression = new CodeMethodInvokeExpression();
methodInfokeExpression.Arguments.Add(paramStringMessageArgument);
methodInfokeExpression.Arguments.Add(paramStringParameterNameArgument);
methodInfokeExpression.Arguments.Add(paramMethodNameArgument);
methodInfokeExpression.MethodReferenceExpression = new CodeMethodReferenceExpression(stringTypeReferenceExpresion, "Format");
CodeArgument paramMessageArgument = new CodeArgument();
paramMessageArgument.Value = methodInfokeExpression;
objectCreateExpression.Arguments.Add(paramMessageArgument);
}
CodeParenthesizedExpression codeParenthesizedExpression = new CodeParenthesizedExpression();
codeParenthesizedExpression.Expression = objectCreateExpression;
CodeThrowStatement throwStatement = new CodeThrowStatement();
throwStatement.ToThrow = codeParenthesizedExpression;
CodeStatementBlock codeStatementThrowBlock = new CodeStatementBlock();
codeStatementThrowBlock.Statements.Add(throwStatement);
#endregion
CodeIfStatement ifStatement = new CodeIfStatement();
ifStatement.Condition = binaryExpression;
ifStatement.TrueStatement = codeStatementThrowBlock;
return ifStatement;
}
#endregion
private static Type[] applicableApplicabilityScopeTypes = {typeof(MethodApplicabilityScope),typeof(PropertyApplicabilityScope),typeof(EventApplicabilityScope),typeof(FileApplicabilityScope)};
public override Type[] ApplicableApplicabilityScopeTypes
{
get
{
return applicableApplicabilityScopeTypes;
}
}
private static RuleViolation[] emptyViolationsList = new RuleViolation[0];
private Type[] targetedCodeElements = {typeof(CodeTypeMethodDeclaration), typeof(CodeTypeIndexerDeclaration), typeof(CodeTypeEventDeclaration), typeof(CodeTypePropertyDeclaration)};
}
}
|