using System;
using System.Xml;
using System.Collections;
using System.Collections.Specialized;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.CommonUIControls;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using AnticipatingMinds.Genesis.KnowledgeManagement;
namespace AnticipatingMinds.KnowledgePack.Threading{
/// <summary>
/// Summary description for AvoidSelfManagedThreads.
/// </summary>
public class AvoidUsingUserCreatedThreadsRuleTemplate : RuleTemplate
{
public AvoidUsingUserCreatedThreadsRuleTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
KnowledgePackLicense.Validate();
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("AvoidUsingUserCreatedThreadsRuleTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("AvoidUsingUserCreatedThreadsRuleTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
// Todo: Add multiple rule types here from XML properties
// probably a case statement
return new AvoidUsingUserCreatedThreadsRule(ruleId,Id,ruleProperties);
}
}
/// <summary>
/// Avoid using System.Threading.Thread class unless you change thread priority.
/// </summary>
/// <remarks>
/// Avoid using System.Threading.Thread class unless you change thread priority. Instead prefer usage
/// of system thread pool (ThreadPool class).
/// </remarks>
public class AvoidUsingUserCreatedThreadsRule : Rule
{
internal AvoidUsingUserCreatedThreadsRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
private class RuleData
{
public StringCollection threadDeclarations = new StringCollection();
public StringCollection customPriorityThreads = new StringCollection();
public RuleViolationCollection violations = new RuleViolationCollection();
}
public CodeDomWalker.WalkerCallbackReturn DiscoverThreadDeclarationsAndPriorityUsage(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType == CodeDomWalker.CallBackNotificationType.OnElement)
{
#region Check if priority of the thread has been changed
//Check if priority of the thread has been changed
if(codeElement is CodeBinaryExpression)
{
CodeBinaryExpression binaryExpression = codeElement as CodeBinaryExpression;
if(binaryExpression.Operator != CodeBinaryOperatorType.Assign)
return CodeDomWalker.WalkerCallbackReturn.NextSibling;
if(binaryExpression.LeftOperand is CodeNamedReferenceExpression)
{
CodeNamedReferenceExpression assignedField = binaryExpression.LeftOperand as CodeNamedReferenceExpression;
if(assignedField.Name == "Priority")
{
//find out the the name of the property or field and add it to the names of modified threads.
if(assignedField.TargetObject != null)
{
string targetName = string.Empty;
if(assignedField.TargetObject is CodeNamedReferenceExpression)
targetName = (assignedField.TargetObject as CodeNamedReferenceExpression).Name;
if(assignedField.TargetObject is CodeVariableReferenceExpression)
targetName = (assignedField.TargetObject as CodeVariableReferenceExpression).VariableName;
RuleData ruleData = applicationData as RuleData;
ruleData.customPriorityThreads.Add(targetName);
}
}
}
}
#endregion Check if priority of the thread has been changed
#region Record Thread declaration as property
if(codeElement is CodeTypePropertyDeclaration)
{
CodeTypePropertyDeclaration propertyDeclaration = codeElement as CodeTypePropertyDeclaration;
string declarationType = propertyDeclaration.ReturnType.TypeName;
if(declarationType == "System.Threading.Thread" || declarationType == "Thread")
{
RuleData ruleData = applicationData as RuleData;
ruleData.threadDeclarations.Add(propertyDeclaration.Name);
}
}
#endregion Record Thread declaration as property
#region Record Thread declaration as field or variable declaration
if(codeElement is CodeTypeFieldDeclaration || codeElement is CodeVariableDeclarationStatement)
{
string declarationType = string.Empty;
CodeVariableDeclarationMemberCollection declarationMembers;
if(codeElement is CodeTypeFieldDeclaration)
{
CodeTypeFieldDeclaration fieldDeclaration = codeElement as CodeTypeFieldDeclaration;
declarationType = fieldDeclaration.DeclarationType.TypeName;
declarationMembers = fieldDeclaration.DeclaredFields;
}
else
{
CodeVariableDeclarationStatement variableDeclaration = codeElement as CodeVariableDeclarationStatement;
declarationType = variableDeclaration.DeclarationType.TypeName;
declarationMembers = variableDeclaration.DeclaredVariables;
}
if(declarationType == "System.Threading.Thread" || declarationType == "Thread")
{
RuleData ruleData = applicationData as RuleData;
foreach(CodeVariableDeclarationMember declarationMember in declarationMembers)
ruleData.threadDeclarations.Add(declarationMember.Name);
}
}
#endregion Record Thread declaration as field or variable declaration
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
public CodeDomWalker.WalkerCallbackReturn AnalyzeThreadUsage(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType == CodeDomWalker.CallBackNotificationType.OnElement)
{
if(codeElement is CodeMethodInvokeExpression)
{
CodeMethodInvokeExpression methodInvokeExpression = codeElement as CodeMethodInvokeExpression;
if(methodInvokeExpression.MethodName == "Start")
{
CodeNamedReferenceExpression methodReference = methodInvokeExpression.MethodReferenceExpression as CodeNamedReferenceExpression;
if(methodReference != null && methodReference.TargetObject != null)
{
string targetName = string.Empty;
if(methodReference.TargetObject is CodeNamedReferenceExpression)
targetName = (methodReference.TargetObject as CodeNamedReferenceExpression).Name;
if(methodReference.TargetObject is CodeVariableReferenceExpression)
targetName = (methodReference.TargetObject as CodeVariableReferenceExpression).VariableName;
RuleData ruleData = applicationData as RuleData;
if(ruleData.threadDeclarations.Contains(targetName) && !ruleData.customPriorityThreads.Contains(targetName))
{
if(IsCodeElementInRuleApplicabilityScope(CodeTypeMemberUtils.GetContainingTypeMember(methodReference)))
{
RuleViolation violation = new RuleViolation(this,
ResourceManager.GetLocalizedString("AvoidUsingUserCreatedThreadsRuleViolation|Description"),
methodInvokeExpression);
violation.Severity = RuleViolation.ViolationSeverity.Suggestion;
ruleData.violations.Add(violation);
}
}
}
}
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
public override RuleViolation[] Analyze(object targetedObject, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
if(targetedObject is CodeTypeDeclaration)
{
RuleData ruleData = new RuleData();
CodeDomWalker.WalkCodeElement(targetedObject as CodeElement,new CodeDomWalker.WalkerCallback(DiscoverThreadDeclarationsAndPriorityUsage),ruleData);
if(ruleData.threadDeclarations.Count != 0)
CodeDomWalker.WalkCodeElement(targetedObject as CodeElement,new CodeDomWalker.WalkerCallback(AnalyzeThreadUsage),ruleData);
if(ruleData.violations.Count != 0)
return ruleData.violations.ToArray();
else
return emptyViolationsList;
}
return emptyViolationsList;
}
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
// TODO: Add AvoidUsingUserCreatedThreadsRule.Correct implementation
}
public override Type[] TargetedCodeElements
{
get
{
return targtedCodeElements;
}
}
public override Type[] ApplicableApplicabilityScopeTypes
{
get
{
return applicableApplicabilityScopeTypes;
}
}
private Type[] targtedCodeElements = new Type[1] {typeof(CodeTypeDeclaration)};
private static RuleViolation[] emptyViolationsList = new RuleViolation[0];
private static Type[] applicableApplicabilityScopeTypes = {typeof(MethodApplicabilityScope),typeof(PropertyApplicabilityScope),typeof(EventApplicabilityScope),typeof(FileApplicabilityScope)};
}
}
|