using System;
using System.Xml;
using System.Collections;
using System.Collections.Specialized;
using AnticipatingMinds.CommonUIControls;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using AnticipatingMinds.Genesis.KnowledgeManagement;
namespace AnticipatingMinds.KnowledgePack.Threading{
/// <summary>
/// Summary description for StaticDoNotCallStaticMethods.
/// </summary>
public class StaticDoNotCallStaticMethodsRuleTemplate : RuleTemplate
{
public StaticDoNotCallStaticMethodsRuleTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
KnowledgePackLicense.Validate();
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("StaticDoNotCallStaticMethodsRuleTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("StaticDoNotCallStaticMethodsRuleTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
// Todo: Add multiple rule types here from XML properties
// probably a case statement
return new StaticDoNotCallStaticMethodsRule(ruleId,Id,ruleProperties);
}
}
/// <summary>
/// Avoid calling static methods that call static methods on the same class.
/// </summary>
/// <remarks>
/// Performance issues can result when a static method in class A calls a static method in class A.
/// If these methods are not factored correctly, performance will suffer because
/// there will be a large amount of redundant synchronization.
/// Excessive use of fine-grained synchronization might negatively
/// impact performance. In addition, it might have a
/// significant negative impact on scalability.
/// </remarks>
public class StaticDoNotCallStaticMethodsRule : Rule
{
internal StaticDoNotCallStaticMethodsRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
private struct RuleData
{
public CodeTypeDeclaration typeDeclaration;
public IDictionary staticMethods;
public RuleViolationCollection violations;
}
private CodeDomWalker.WalkerCallbackReturn LockLookupWalkerCallback(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType == CodeDomWalker.CallBackNotificationType.OnElement)
{
if(codeElement is CodeLockStatement)
return CodeDomWalker.WalkerCallbackReturn.Cancel;
if(codeElement is CodeMethodInvokeExpression)
{
string calledMethod = CodeNamedReferenceExpressionUtils.GetTargetReferencesAsString((codeElement as CodeMethodInvokeExpression).MethodReferenceExpression as CodeNamedReferenceExpression);
if(calledMethod == "Threading.Monitor.Enter" || calledMethod == "Monitor.Enter" || calledMethod == "System.Threading.Monitor.Enter")
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private bool MemberHasLock(CodeTypeMemberDeclaration typeMember)
{
//if we have been canceled - we found a lock
//otherwise we did not find anything
if(CodeDomWalker.WalkCodeElement(typeMember,new CodeDomWalker.WalkerCallback(LockLookupWalkerCallback)) == CodeDomWalker.WalkerCallbackReturn.Cancel)
return true;
else
return false;
}
/// <summary>
/// Builds a collection of static type members. When done associates a collection with type
/// declaration code element in 'TypeStaticMembersWithLocksByName' dictionary entry.
/// If collection already associated with type declaration - return
/// existant colletion.
/// </summary>
/// <param name="typeDeclaration"></param>
/// <returns></returns>
private IDictionary GetStaticTypeMembers(CodeTypeDeclaration typeDeclaration)
{
//Build a collection of static type members. When done associate such a collection with type code element to
//avoid uneccessary rebuild when examining different members of the same type.
if(typeDeclaration.ApplicationData.Contains("TypeStaticMembersWithLocksByName"))
return typeDeclaration.ApplicationData["TypeStaticMembersWithLocksByName"] as IDictionary;
IDictionary staticMembersByName = (new Hashtable()) as IDictionary;
typeDeclaration.ApplicationData["TypeStaticMembersWithLocksByName"] = staticMembersByName;
CodeTypeMemberDeclarationCollection typeMembers = null;
if(typeDeclaration is CodeClassDeclaration)
typeMembers = (typeDeclaration as CodeClassDeclaration).Members;
if(typeDeclaration is CodeInterfaceDeclaration)
typeMembers = (typeDeclaration as CodeInterfaceDeclaration).Members;
if(typeDeclaration is CodeStructDeclaration)
typeMembers = (typeDeclaration as CodeStructDeclaration).Members;
if(typeMembers != null)
{
foreach(CodeTypeMemberDeclaration typeMember in typeMembers)
{
StringCollection declaredNames = new StringCollection();
if((typeMember.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Static) != 0)
{
if(!MemberHasLock(typeMember))
continue;
if(typeMember is CodeTypeEventDeclaration)
{
declaredNames.Add((typeMember as CodeTypeEventDeclaration).Name);
}
if(typeMember is CodeTypePropertyDeclaration)
{
declaredNames.Add((typeMember as CodeTypePropertyDeclaration).Name);
}
if(typeMember is CodeTypeMethodDeclaration)
{
declaredNames.Add((typeMember as CodeTypeMethodDeclaration).Name);
}
if(typeMember is CodeTypeEventDeclaration)
{
declaredNames.Add((typeMember as CodeTypeEventDeclaration).Name);
}
if(typeMember is CodeTypeFieldDeclaration)
{
foreach(CodeVariableDeclarationMember declarationMember in (typeMember as CodeTypeFieldDeclaration).DeclaredFields)
declaredNames.Add(declarationMember.Name);
}
if(typeMember is CodeTypeEventListDeclaration)
{
foreach(CodeVariableDeclarationMember declarationMember in (typeMember as CodeTypeEventListDeclaration).DeclaredEvents)
declaredNames.Add(declarationMember.Name);
}
foreach(string name in declaredNames)
if(!staticMembersByName.Contains(name))
staticMembersByName.Add(name,typeMember);
}
}
}
return staticMembersByName;
}
public override RuleViolation[] Analyze(object targetedObject, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
CodeTypeMemberDeclaration typeMemberDeclaration = targetedObject as CodeTypeMemberDeclaration;
if(!IsCodeElementInRuleApplicabilityScope(typeMemberDeclaration))
return emptyViolationsList;
//Only intrested in static methods
if((typeMemberDeclaration.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Static) == 0)
return emptyViolationsList;
if(!(typeMemberDeclaration is CodeTypeMethodDeclaration ||
typeMemberDeclaration is CodeTypeOperatorDeclaration ||
typeMemberDeclaration is CodeTypePropertyDeclaration))
return emptyViolationsList;
if(typeMemberDeclaration.DeclaringType == null)
return emptyViolationsList;
RuleData ruleData = new RuleData();
ruleData.staticMethods = GetStaticTypeMembers(typeMemberDeclaration.DeclaringType);
ruleData.violations = new RuleViolationCollection();
ruleData.typeDeclaration = typeMemberDeclaration.DeclaringType;
//Verify that this type member is in the list of memebrs with locks
if(typeMemberDeclaration is CodeTypeEventDeclaration)
{
if(!ruleData.staticMethods.Contains((typeMemberDeclaration as CodeTypeEventDeclaration).Name))
return emptyViolationsList;
}
if(typeMemberDeclaration is CodeTypePropertyDeclaration)
{
if(!ruleData.staticMethods.Contains((typeMemberDeclaration as CodeTypePropertyDeclaration).Name))
return emptyViolationsList;
}
if(typeMemberDeclaration is CodeTypeMethodDeclaration)
{
if(!ruleData.staticMethods.Contains((typeMemberDeclaration as CodeTypeMethodDeclaration).Name))
return emptyViolationsList;
}
if(typeMemberDeclaration is CodeTypeEventDeclaration)
{
if(!ruleData.staticMethods.Contains((typeMemberDeclaration as CodeTypeEventDeclaration).Name))
return emptyViolationsList;
}
CodeDomWalkerContext walkerContex = new CodeDomWalkerContext();
walkerContex.ExcludeCodeElement(typeMemberDeclaration.DeclaringType);
CodeDomWalker.WalkCodeElement( typeMemberDeclaration , new CodeDomWalker.WalkerCallback(this.MyWalkerCallback), walkerContex, ruleData);
if(ruleData.violations.Count == 0)
return emptyViolationsList;
return ruleData.violations.ToArray();
}
private CodeDomWalker.WalkerCallbackReturn MyWalkerCallback(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType == CodeDomWalker.CallBackNotificationType.OnElement)
{
if(codeElement is CodeMethodInvokeExpression)
{
RuleData ruleData = (RuleData)applicationData;
CodeNamedReferenceExpression methodReference = (codeElement as CodeMethodInvokeExpression).MethodReferenceExpression as CodeNamedReferenceExpression;
string targetCode = string.Empty;
if(methodReference != null)
{
if(methodReference.TargetObject != null && methodReference.TargetObject is CodeNamedReferenceExpression)
targetCode = CodeNamedReferenceExpressionUtils.GetTargetReferencesAsString(methodReference.TargetObject as CodeNamedReferenceExpression);
if(methodReference.TargetObject != null && methodReference.TargetObject is CodeTypeReferenceExpression)
targetCode = (methodReference.TargetObject as CodeTypeReferenceExpression).ReferencedType.TypeName;
if(targetCode.Length == 0 ||
targetCode == ruleData.typeDeclaration.Name ||
targetCode == ruleData.typeDeclaration.FullName)
{
if(ruleData.staticMethods.Contains(methodReference.Name))
{
RuleViolation violation = new RuleViolation(this,
string.Format(ResourceManager.GetLocalizedString( "StaticDoNotCallStaticMethodsViolation|Description"),methodReference.Name),
codeElement);
violation.Severity = RuleViolation.ViolationSeverity.Suggestion;
ruleData.violations.Add(violation);
}
}
}
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
// TODO: Add StaticDoNotCallStaticMethodsRule.Correct implementation
}
public override Type[] TargetedCodeElements
{
get
{
return targtedCodeElements;
}
}
public override Type[] ApplicableApplicabilityScopeTypes
{
get
{
return applicableApplicabilityScopeTypes;
}
}
private static Type[] applicableApplicabilityScopeTypes = {typeof(MethodApplicabilityScope),typeof(PropertyApplicabilityScope),typeof(EventApplicabilityScope),typeof(FileApplicabilityScope)};
private Type[] targtedCodeElements = new Type[1] {typeof(CodeTypeMemberDeclaration)};
private static RuleViolation[] emptyViolationsList = new RuleViolation[0];
}
}
|