using System;
using System.Collections;
using AnticipatingMinds.Genesis.KnowledgeManagement;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using System.Threading;
using System.Text.RegularExpressions;
namespace AnticipatingMinds.KnowledgePack.Design{
public class IDisposablePatternTemplate : RuleTemplate
{
public IDisposablePatternTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("IDisposablePatternTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("IDisposablePatternTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
return new IDisposablePatternRule(ruleId, Id, ruleProperties);
}
public override AnticipatingMinds.CommonUIControls.PropertyPage[] GetRulePropertiesUI(IDictionary ruleProperties)
{
AnticipatingMinds.CommonUIControls.PropertyPage[] pages = new AnticipatingMinds.CommonUIControls.PropertyPage[3];
pages[0] = new ResourceActivateMethodsPropertyPage(ruleProperties);
pages[1] = new ResourceTypes(ruleProperties);
pages[2] = new IDisposableRulePropertyPage(ruleProperties);
return pages;
}
}
public class IDisposablePatternRule : Rule
{
#region Rule Property
public new class PropertyName : Rule.PropertyName
{
public const string AllocateDeAllocateMethodNames = "AllocateDeAllocateMethodNames";
public const string ResourceNames = "ResourceNames";
public const string NotBeAnalyzedClassesList = "NotBeAnalyzedClassesList";
}
private ArrayList ResourceNames
{
get{return GetProperty(PropertyName.ResourceNames, new ArrayList()) as ArrayList;}
set{SetProperty(PropertyName.ResourceNames, value);}
}
private Hashtable AllocateDeAllocateMethodNames
{
get{return GetProperty(PropertyName.AllocateDeAllocateMethodNames, new Hashtable()) as Hashtable;}
set{SetProperty(PropertyName.AllocateDeAllocateMethodNames, value);}
}
private ArrayList NotBeAnalyzedClassesList
{
get{ return GetProperty(PropertyName.NotBeAnalyzedClassesList, new ArrayList()) as ArrayList;}
set{ SetProperty(PropertyName.NotBeAnalyzedClassesList, value);}
}
#endregion
internal IDisposablePatternRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
public override Type[] TargetedCodeElements
{
get
{
return targetedCodeElements;
}
}
public struct ViolationName
{
public const string Allocate = "Allocate";
public const string Resource = "Resource";
public const string IDisposable = "IDisposable";
public const string ResourceTemplate = "<%resource%>";
}
private class RuleData
{
public RuleViolationCollection violations = new RuleViolationCollection();
public bool IsDisposablePatternImplement = false;
public CodeMethodInvokeExpression MethodInvokeReferenceInConfig = null;
public CodeAssembly Assembly = null;
}
public override RuleViolation[] Analyze(object codeElement, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
CodeTypeDeclaration typeDeclaration = codeElement as CodeTypeDeclaration;
if(typeDeclaration == null || typeDeclaration is AnticipatingMinds.Genesis.AspNetDom.AspNetClassDeclaration)
return emptyViolationsList;
if(typeDeclaration == null
|| !IsCodeElementInRuleApplicabilityScope(typeDeclaration)
|| !DesignUtils.CheckNoreAnalyzedClasses(typeDeclaration.TypeInfo, codeElement as CodeElement, this.NotBeAnalyzedClassesList)
)
return emptyViolationsList;
RuleData ruleData = new RuleData();
ruleData.Assembly = typeDeclaration.CompileUnit.Assembly;
ruleData.IsDisposablePatternImplement = false;
// If type implement IDisposable Pattern
DetectIDisposabeleInterface(ruleData, typeDeclaration);
#region Detect call allocate method
if(!ruleData.IsDisposablePatternImplement)
{
foreach(string allocateMethod in this.AllocateDeAllocateMethodNames.Keys)
{
DetectAllocateReferences(ruleData, typeDeclaration, allocateMethod);
}
}
#endregion
#region Detect IDisposable interface
if(ruleData.violations.Count == 0 && !ruleData.IsDisposablePatternImplement)
{
DetectIDisposabeleInterfaceMember(ruleData, typeDeclaration);
}
#endregion
#region Detect resource type
if(ruleData.violations.Count == 0 && !ruleData.IsDisposablePatternImplement)
{
DetectResourcesTypes(ruleData, typeDeclaration);
}
#endregion
if(ruleData.violations.Count != 0)
return ruleData.violations.ToArray();
else
return emptyViolationsList;
}
#region Get Deallocate method Invoke from config
private CodeMethodInvokeExpression GetMethodInvokeFromConfig(string allocatedMethod, RuleData ruleData)
{
if(ruleData.MethodInvokeReferenceInConfig == null)
{
string deAllocateCode = this.AllocateDeAllocateMethodNames[allocatedMethod].ToString();
deAllocateCode = deAllocateCode + "();";
AnticipatingMinds.Genesis.CodeParser.CSharpParser deAllocateParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser(deAllocateCode, ruleData.Assembly.AssemblyFileName, ruleData.Assembly);
CodeStatementBlock statement = deAllocateParser.ParseStatements(new ManualResetEvent(false));
CodeDomWalker.WalkCodeElement(statement ,new CodeDomWalker.WalkerCallback(FindMethodInvokeInConfig), ruleData);
}
return ruleData.MethodInvokeReferenceInConfig;
}
private CodeDomWalker.WalkerCallbackReturn FindMethodInvokeInConfig(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext, object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
RuleData ruleData = applicationData as RuleData;
if(codeElement is CodeMethodInvokeExpression)
{
ruleData.MethodInvokeReferenceInConfig = codeElement as CodeMethodInvokeExpression;
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
#endregion
#region Detect call allocate method
private void DetectAllocateReferences(RuleData ruleData, CodeTypeDeclaration typeDeclaration, string allocatedMethod)
{
// find all reference for allocated methods
CodeExpressionCollection allocateCollection = CodeNamedReferenceExpressionUtils.FindReferenceTo(typeDeclaration, allocatedMethod);
this.GetMethodInvokeFromConfig( allocatedMethod, ruleData);
foreach(CodeNamedReferenceExpression allocate in allocateCollection)
{
if(allocate == null) continue;
// check for reference only current type
if(!(allocate.TargetObject == null || (allocate.TargetObject is CodeThisReferenceExpression)))
{
continue;
}
// find parent CodeStatementBlock
CodeElement parentAllocate = allocate.Parent;
while(parentAllocate != null && !(parentAllocate.Parent is CodeStatementBlock)) parentAllocate = parentAllocate.Parent;
if(parentAllocate == null) continue;
CodeStatementBlock parentBlock = parentAllocate.Parent as CodeStatementBlock;
// index if referent allocate method
int indexAllocate = parentBlock.Statements.IndexOf(parentAllocate as CodeStatement);
int indexDeAllocate = -1;
if(this.AllocateDeAllocateMethodNames[allocatedMethod].ToString().Length != 0)
{
string deAllocateName = (ruleData.MethodInvokeReferenceInConfig != null)? ruleData.MethodInvokeReferenceInConfig.MethodName : AllocateDeAllocateMethodNames[allocatedMethod].ToString();
CodeExpressionCollection deAllocateCollection = CodeNamedReferenceExpressionUtils.FindReferenceTo(parentBlock, deAllocateName);
foreach(CodeNamedReferenceExpression deAllocate in deAllocateCollection)
{
CodeElement parent = CodeStatementUtils.GetElementStatement(deAllocate);
while(parent != null && !parent.Parent.Equals(parentBlock)) parent = parent.Parent;
indexDeAllocate = parentBlock.Statements.IndexOf(parent as CodeStatement);
}
}
if(indexAllocate > indexDeAllocate)
{
CreateViolation(ruleData, typeDeclaration, allocatedMethod, ViolationName.Allocate);
return;
}
}
}
#endregion
#region Detect resource type
private void DetectResourcesTypes(RuleData ruleData, CodeTypeDeclaration typeDeclaration)
{
// Search all field that declared as user defenition Resource
foreach(string resourceName in this.ResourceNames)
{
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeFieldDeclaration
&& (member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo != null
&& (member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo.FullName == resourceName
)
{
CreateViolation(ruleData, typeDeclaration, member, ViolationName.Resource);
}
}
}
}
#endregion
#region Detect IDisposable Pattern
private void DetectIDisposabeleInterface(RuleData ruleData, CodeTypeDeclaration typeDeclaration)
{
// Detect member for IDisposable pattern
bool isDisposeBoolContains = false;
bool isDestructorContains = false;
// if type implement "System.IDisposable"
CodeAssemblyTypeManager typeManager = typeDeclaration.GetAssemblyTypeManager();
if(typeManager != null
&& typeManager.DoesTypeImplementInterface(typeDeclaration.FullName, "System.IDisposable"))
{
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeDestructorDeclaration)
{
// detect destructor
isDestructorContains = true;
}
if(member is CodeTypeMethodDeclaration
&& ((member as CodeTypeMethodDeclaration).Name == "Dispose" || (member as CodeTypeMethodDeclaration).Name == "IDisposable.Dispose" || (member as CodeTypeMethodDeclaration).Name == "System.IDisposable.Dispose")
&& (member as CodeTypeMethodDeclaration).ReturnType.TypeName == "System.Void"
)
{
CodeTypeMethodDeclaration disposeMethod = member as CodeTypeMethodDeclaration;
if(disposeMethod.Parameters.Count == 1)
{
//detect {protected virtual void Dispose(bool)}
#region Analyze argument
if(disposeMethod.Parameters[0].Type.IsArray == false
&& disposeMethod.Parameters[0].Type.TypeInfo != null
&& disposeMethod.Parameters[0].Type.TypeInfo.FullName == "System.Boolean"
&& disposeMethod.Parameters[0].IsParameterArray == false
)
{
isDisposeBoolContains = true;
}
#endregion
}
}
}
if(typeDeclaration is CodeStructDeclaration) isDestructorContains = true;
if(isDisposeBoolContains && isDestructorContains)
{
ruleData.IsDisposablePatternImplement = true;
}
}
}
#endregion
#region Detect IDisposable field interface
private void DetectIDisposabeleInterfaceMember(RuleData ruleData, CodeTypeDeclaration typeDeclaration)
{
// Search all field that declared as type for implament IDisposable interface
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeFieldDeclaration
&& (member as CodeTypeFieldDeclaration).DeclarationType != null
&& (member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo != null
)
{
CodeAssemblyTypeManager typeManager = (member as CodeTypeFieldDeclaration).DeclarationType.GetAssemblyTypeManager();
if(typeManager != null
&& typeManager.DoesTypeImplementInterface((member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo.FullName, "System.IDisposable")
&& !typeManager.IsTypeSubclassOf((member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo.FullName, "System.ComponentModel.Component")
)
{
CreateViolation(ruleData, typeDeclaration, member, ViolationName.IDisposable);
}
}
}
}
#endregion
private void CreateViolation(RuleData ruleData, CodeTypeDeclaration typeDeclaration, object violationData, string violationName)
{
// Only one violations for type
if(ruleData.violations.Count > 0) return;
RuleViolation violation = new RuleViolation(this, typeDeclaration);
violation.Description = ResourceManager.GetLocalizedString("IDisposablePatternTemplate|"+violationName, typeDeclaration.FullName);
if(violationName == ViolationName.Resource)
{
violation.Severity = RuleViolation.ViolationSeverity.Error;
}
else{
violation.Severity = RuleViolation.ViolationSeverity.Warning;
}
if(IsCorrectable(typeDeclaration))
{
RuleViolationCorrection violationCorrection;
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("IDisposablePatternTemplate|Correction"), false, false);
violationCorrection.CorrectionData["CodeTypeDeclaration"] = typeDeclaration;
violationCorrection.CorrectionData["ViolationName"] = violationName;
if(violationName == ViolationName.Allocate)
{
violationCorrection.CorrectionData["Allocate"] = violationData;
violationCorrection.CorrectionData["DeAllocate"] = this.AllocateDeAllocateMethodNames[violationData];
}
}
ruleData.violations.Add(violation);
}
private bool IsCorrectable(CodeTypeDeclaration typeDeclaration)
{
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeMethodDeclaration
&& (member as CodeTypeMethodDeclaration).Name == "Dispose"
&& (member as CodeTypeMethodDeclaration).Parameters.Count <= 1
&& (member as CodeTypeMethodDeclaration).ReturnType != null
&& (member as CodeTypeMethodDeclaration).ReturnType.TypeName != "System.Void"
)
{
return false;
}
}
return true;
}
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
codeEffector.BeginCodeChanges("Convert type to IDisposable pattern");
foreach(RuleViolationCorrection requestedCorrection in requestedCorrections)
{
if(requestedCorrection.Violation.IsFixed)
continue;
CodeTypeDeclaration typeDeclaration = requestedCorrection.CorrectionData["CodeTypeDeclaration"] as CodeTypeDeclaration;
string violationName = requestedCorrection.CorrectionData["ViolationName"].ToString();
string dataDeAllocate = "";
if(violationName == ViolationName.Allocate)
{
dataDeAllocate = requestedCorrection.CorrectionData["DeAllocate"].ToString();
}
if(!CheckInterfaceExists(typeDeclaration))
{
AddInterface(typeDeclaration, codeEffector);
}
AddInstanceField(typeDeclaration, codeEffector, dataDeAllocate);
requestedCorrection.Violation.IsFixed = true;
}
try
{
codeEffector.CommitCodeChanges();
}
catch(Exception)
{
codeEffector.RollbackCodeChanges();
throw;
}
//Before we leave corrections let's rebuild assembly metadata making sure that all that new code we
//inserted is having correct information
Hashtable assembliesChanged = new Hashtable();
foreach(RuleViolationCorrection requestedCorrection in requestedCorrections)
{
CodeTypeDeclaration typeDeclaration = requestedCorrection.CorrectionData["CodeTypeDeclaration"] as CodeTypeDeclaration;
if(!assembliesChanged.Contains(typeDeclaration.CompileUnit.Assembly))
assembliesChanged.Add(typeDeclaration.CompileUnit.Assembly,null);
}
foreach(CodeAssembly assembly in assembliesChanged.Keys)
{
assembly.TypeManager.BuildAssemblyMetadata(new ManualResetEvent(false));
}
}
private bool CheckInterfaceExists(CodeTypeDeclaration typeDeclaration)
{
CodeAssemblyTypeManager typeManager = typeDeclaration.GetAssemblyTypeManager();
if(typeManager != null
&& typeManager.DoesTypeImplementInterface(typeDeclaration.FullName, "System.IDisposable"))
{
return true;
}
return false;
}
private void AddInterface(CodeTypeDeclaration typeDeclaration, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector)
{
CodeTypeReferenceCollection bases = new CodeTypeReferenceCollection(new CodeTypeReference[]{new CodeTypeReference(CodeTypeReferenceUtils.GetShortestTypeNameReference( typeDeclaration, "System.IDisposable"))});
if(typeDeclaration is CodeClassDeclaration)
{
CodeClassDeclaration classDeclaration = typeDeclaration as CodeClassDeclaration;
codeEffector.AddCodeElements(bases, classDeclaration, classDeclaration.BaseTypes, classDeclaration.BaseTypes.Count);
}
else if(typeDeclaration is CodeStructDeclaration)
{
CodeStructDeclaration structDeclaration = typeDeclaration as CodeStructDeclaration;
codeEffector.AddCodeElements(bases, structDeclaration, structDeclaration.Interfaces, structDeclaration.Interfaces.Count);
}
codeEffector.PerformCodeChanges();
}
private void AddInstanceField(CodeTypeDeclaration typeDeclaration, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, string dataDeAllocate)
{
CodeTypeMemberDeclarationCollection memberCollection = new CodeTypeMemberDeclarationCollection();
#region Create Dispose() method
CodeTypeMethodDeclaration emptyDispose = new CodeTypeMethodDeclaration();
emptyDispose.Name = "Dispose";
emptyDispose.ReturnType = new CodeTypeReference(typeof(void));
emptyDispose.Modifiers = CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public ;
string emptyDisposeContent = String.Format(@"Dispose(true); GC.SuppressFinalize(this);");
AnticipatingMinds.Genesis.CodeParser.CSharpParser emptyDisposeContentParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser(emptyDisposeContent, typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
emptyDispose.Statements = emptyDisposeContentParser.ParseStatements(new ManualResetEvent(false));
#endregion
#region Create desctructor
CodeTypeDestructorDeclaration destructor = new CodeTypeDestructorDeclaration();
destructor.Parent = typeDeclaration;
string destructorContent = String.Format("Dispose(false)");
AnticipatingMinds.Genesis.CodeParser.CSharpParser destructorParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser(destructorContent, typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
destructor.Statements = destructorParser.ParseStatements(new ManualResetEvent(false));
#endregion
#region Create Disposable(bool) method
bool baseDisposableExists = this.AnalyzeBaseClass(typeDeclaration);
CodeTypeMethodDeclaration dispose = new CodeTypeMethodDeclaration();
dispose.Name = "Dispose";
if(typeDeclaration is CodeClassDeclaration){
dispose.Modifiers = CodeTypeMemberDeclaration.MemberDeclarationModifiers.Protected ;
if(baseDisposableExists)
{
dispose.Modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Override;
}
else
{
dispose.Modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Virtual;
}
}
dispose.ReturnType = new CodeTypeReference(typeof(void));
CodeMethodParameter boolParamenter = new CodeMethodParameter(new CodeTypeReference(typeof(bool)), "disposing");
dispose.Parameters.Add(boolParamenter);
dispose.Statements = new CodeStatementBlock();
#endregion
// check for Dispose() member
CodeTypeMemberDeclaration existsDispose = CheckTypeForDisposeMember(typeDeclaration, codeEffector);
// add new members to type
if(NotExistsMethod(typeDeclaration, destructor))
{
memberCollection.Add(destructor);
}
else{
// Analize destructor for find call Dispose(bool) method
AnalizeDestructor(typeDeclaration, codeEffector);
}
bool addBoolDisposeMember = false;
if(NotExistsMethod(typeDeclaration, dispose))
{
if(existsDispose != null
&& (existsDispose as CodeTypeMethodDeclaration).Statements != null
&& (existsDispose as CodeTypeMethodDeclaration).Statements.Statements.Count != 0)
{
CodeStatementBlock disposeContent = (existsDispose as CodeTypeMethodDeclaration).Statements.Clone() as CodeStatementBlock;
dispose.Statements = MoveStatementFromDispose(typeDeclaration, disposeContent, boolParamenter, dataDeAllocate, baseDisposableExists);
}
else
{
addBoolDisposeMember = true;
}
memberCollection.Add(dispose);
}
if(existsDispose == null)
{
// Check for parent Type implement IDisposable Interface
bool baseImplementIDisposable = BaseImplementIDisposable(typeDeclaration);
if(!baseImplementIDisposable)
{
memberCollection.Add(emptyDispose);
}
}
else
{
if((existsDispose.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Abstract) != 0)
{
emptyDispose.Modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Virtual ;
codeEffector.ReplaceCodeElement(existsDispose, emptyDispose);
}
else
{
codeEffector.ReplaceCodeElement((existsDispose as CodeTypeMethodDeclaration).Statements, emptyDisposeContentParser.ParseStatements(new ManualResetEvent(false)));
}
codeEffector.PerformCodeChanges();
}
CodeTypeMemberDeclarationCollection typeMembers = CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration);
int insertIndex = 0;
while(typeMembers.Count < insertIndex && (typeMembers[insertIndex] is CodeTypeConstructorDeclaration))
insertIndex++;
codeEffector.AddCodeElements(memberCollection, typeDeclaration, typeMembers, insertIndex);
codeEffector.PerformCodeChanges();
// insert content to bool Dispose member
if(addBoolDisposeMember)
{
GetStatementToDispose(dispose.Statements, codeEffector, dataDeAllocate, typeDeclaration, boolParamenter, baseDisposableExists);
}
}
private void AnalizeDestructor(CodeTypeDeclaration typeDeclaration, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector)
{
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeDestructorDeclaration)
{
CodeExpressionCollection disposeCollection = CodeNamedReferenceExpressionUtils.FindReferenceTo(member, "Dispose");
foreach(CodeNamedReferenceExpression dispose in disposeCollection)
{
if(dispose == null) continue;
if(dispose is CodeMethodReferenceExpression
&& (dispose as CodeMethodReferenceExpression).MethodInfo != null
)
{
return;
}
}
string destructorContent = String.Format("Dispose(false)");
AnticipatingMinds.Genesis.CodeParser.CSharpParser destructorParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser(destructorContent, typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
codeEffector.AddCodeElements(destructorParser.ParseStatements(new ManualResetEvent(false)).Statements,(member as CodeTypeDestructorDeclaration).Statements,(member as CodeTypeDestructorDeclaration).Statements.Statements, (member as CodeTypeDestructorDeclaration).Statements.Statements.Count);
codeEffector.PerformCodeChanges();
}
}
}
private bool BaseImplementIDisposable(CodeTypeDeclaration typeDeclaration)
{
bool dispose = false;
// if class child of other class than implement IDisposable interface
if(typeDeclaration is CodeClassDeclaration)
{
CodeClassDeclaration classDeclaration = typeDeclaration as CodeClassDeclaration;
if(classDeclaration.BaseTypes.Count != 0
&& classDeclaration.BaseTypes[0] != null
&& classDeclaration.BaseTypes[0].TypeInfo != null)
{
CodeTypeInfo baseInfo = classDeclaration.BaseTypes[0].TypeInfo;
CodeAssemblyTypeManager typeManager = typeDeclaration.GetAssemblyTypeManager();
if(typeManager != null
&& typeManager.DoesTypeImplementInterface(baseInfo.FullName, "System.IDisposable"))
{
return true;
}
}
}
return dispose;
}
private CodeStatementBlock MoveStatementFromDispose(CodeTypeDeclaration typeDeclaration, CodeStatementBlock disposeContent, CodeMethodParameter boolParamenter, string dataDeAllocate, bool baseDisposableExists)
{
CodeStatementBlock block = new CodeStatementBlock();
CodeIfStatement ifStatement = new CodeIfStatement();
CodeStatementBlock blockDeallocate = GetCodeToInsert(dataDeAllocate, typeDeclaration);
CodeMethodParameterReferenceExpression parameter = new CodeMethodParameterReferenceExpression();
parameter.MethodParameter = boolParamenter;
ifStatement.Condition = parameter;
disposeContent.Statements[0].Comment = new CodeComment();
disposeContent.Statements[0].Comment.Lines.Add("TODO: Add Disposable implementation");
if(dataDeAllocate.Length != 0 && blockDeallocate == null) disposeContent.Statements[0].Comment.Lines.Add(dataDeAllocate);
CodeStatementBlock ifStatementBlock = disposeContent;
if(blockDeallocate != null && blockDeallocate.Statements.Count != 0)
{
ifStatementBlock.Statements.AddRange(blockDeallocate.Statements);
}
ifStatement.TrueStatement = ifStatementBlock;
block = new CodeStatementBlock();
block.Statements.Add(ifStatement);
if(baseDisposableExists)
{
AnticipatingMinds.Genesis.CodeParser.CSharpParser callBaseParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser("base.Dispose(disposing)", typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
CodeStatementBlock callBaseStatement = callBaseParser.ParseStatements(new ManualResetEvent(false));
block.Statements.Add(callBaseStatement.Statements[0]);
}
return block;
}
private CodeTypeMemberDeclaration CheckTypeForDisposeMember(CodeTypeDeclaration typeDeclaration, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector)
{
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeMethodDeclaration
&& ((member as CodeTypeMethodDeclaration).Name == "Dispose" || (member as CodeTypeMethodDeclaration).Name == "IDisposable.Dispose" || (member as CodeTypeMethodDeclaration).Name == "System.IDisposable.Dispose")
&& (member as CodeTypeMethodDeclaration).ReturnType.TypeName == "System.Void"
&& (member as CodeTypeMethodDeclaration).Parameters.Count == 0
)
{
return member;
}
}
return null;
}
#region AnalyzeBaseClass
private bool AnalyzeBaseClass(CodeTypeDeclaration typeDeclaration)
{
bool disposeBool = false;
// if class child of other class than implement IDisposable interface
if(typeDeclaration is CodeClassDeclaration)
{
CodeClassDeclaration classDeclaration = typeDeclaration as CodeClassDeclaration;
if(classDeclaration.BaseTypes.Count != 0
&& classDeclaration.BaseTypes[0] != null
&& classDeclaration.BaseTypes[0].TypeInfo != null)
{
CodeTypeInfo baseInfo = classDeclaration.BaseTypes[0].TypeInfo;
if(baseInfo.IsInterface) return false;
foreach(CodeMethodInfo mi in baseInfo.GetMethods())
{
if(mi.Name == "Dispose"
&& mi.GetParameters().Length == 1
&& mi.GetParameters().GetValue(0) is CodeParameterInfo
&& (mi.GetParameters().GetValue(0) as CodeParameterInfo).TypeName == "System.Boolean"
&& mi.ReturnType == "System.Void"
)
{
disposeBool = true;
}
}
}
}
return disposeBool;
}
#endregion
private CodeStatementBlock GetCodeToInsert(string dataDeAllocate, CodeTypeDeclaration typeDeclaration)
{
if(dataDeAllocate.Length != 0)
{
if(dataDeAllocate.IndexOf(ViolationName.ResourceTemplate) != -1
&& dataDeAllocate.IndexOf(ViolationName.ResourceTemplate) == dataDeAllocate.LastIndexOf(ViolationName.ResourceTemplate))
{
InsertResourceNameForm frm = new InsertResourceNameForm(dataDeAllocate);
if(frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string param = frm.ResourceTextBox.Text.Trim();
AnticipatingMinds.Genesis.CodeParser.CSharpParser disposeContentParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser(dataDeAllocate.Replace(ViolationName.ResourceTemplate, param), typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
return disposeContentParser.ParseStatements(new ManualResetEvent(false));
}
}
}
return null;
}
private void GetStatementToDispose(CodeStatementBlock disposeBlock, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, string dataDeAllocate, CodeTypeDeclaration typeDeclaration, CodeMethodParameter boolParamenter, bool baseDisposableExists)
{
CodeStatementBlock blockDeallocate = GetCodeToInsert(dataDeAllocate, typeDeclaration);
CodeEmptyStatement emptyStatement = new CodeEmptyStatement();
CodeIfStatement ifStatement = new CodeIfStatement();
CodeMethodParameterReferenceExpression parameter = new CodeMethodParameterReferenceExpression();
parameter.MethodParameter = boolParamenter;
ifStatement.Condition = parameter;
emptyStatement.Comment = new CodeComment();
emptyStatement.Comment.Lines.Add("TODO: Add Disposable implementation");
if(dataDeAllocate.Length != 0 && blockDeallocate == null) emptyStatement.Comment.Lines.Add(dataDeAllocate);
CodeStatementBlock ifStatementBlock = new CodeStatementBlock();
ifStatementBlock.Statements.Add(emptyStatement);
CodeStatementBlock callDispose = this.CallDisposeForIDisposableFields(typeDeclaration);
if(blockDeallocate != null && blockDeallocate.Statements.Count != 0)
{
ifStatementBlock.Statements.AddRange(blockDeallocate.Statements);
}
if(callDispose.Statements.Count != 0)
{
ifStatementBlock.Statements.AddRange(callDispose.Statements);
}
ifStatement.TrueStatement = ifStatementBlock;
CodeStatementBlock block = new CodeStatementBlock();
block.Statements.Add(ifStatement);
// if in base class exists Dispose(bool) method
if(baseDisposableExists)
{
AnticipatingMinds.Genesis.CodeParser.CSharpParser callBaseParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser("base.Dispose(disposing)", typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
CodeStatementBlock callBaseStatement = callBaseParser.ParseStatements(new ManualResetEvent(false));
block.Statements.Add(callBaseStatement.Statements[0]);
}
codeEffector.ReplaceCodeElement(disposeBlock, block);
codeEffector.PerformCodeChanges();
codeEffector.DeleteCodeElement(emptyStatement);
codeEffector.PerformCodeChanges();
}
private CodeStatementBlock CallDisposeForIDisposableFields(CodeTypeDeclaration typeDeclaration)
{
string textCallDisposeForIDisposableFields = "";
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeFieldDeclaration
&& (member as CodeTypeFieldDeclaration).DeclarationType != null
&& (member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo != null
)
{
CodeAssemblyTypeManager typeManager = (member as CodeTypeFieldDeclaration).DeclarationType.GetAssemblyTypeManager();
if(typeManager != null
&& typeManager.DoesTypeImplementInterface((member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo.FullName, "System.IDisposable")
&& !typeManager.IsTypeSubclassOf((member as CodeTypeFieldDeclaration).DeclarationType.TypeInfo.FullName, "System.ComponentModel.Component")
)
{
foreach(CodeVariableDeclarationMember variable in (member as CodeTypeFieldDeclaration).DeclaredFields){
textCallDisposeForIDisposableFields += String.Format("if({0} != null){1}({0} as IDisposable).Dispose(); {0} = null;{2}", variable.Name, "{", "}");
}
}
}
}
AnticipatingMinds.Genesis.CodeParser.CSharpParser callDisposeParser = new AnticipatingMinds.Genesis.CodeParser.CSharpParser(textCallDisposeForIDisposableFields, typeDeclaration.CompileUnit.Assembly.AssemblyFileName, typeDeclaration.CompileUnit.Assembly);
return callDisposeParser.ParseStatements(new ManualResetEvent(false));
}
private bool NotExistsMethod(CodeTypeDeclaration typeDeclaration, CodeTypeMethodDeclaration method)
{
if(typeDeclaration is CodeStructDeclaration && method is CodeTypeDestructorDeclaration)
{
return false;
}
foreach(CodeTypeMemberDeclaration member in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
if(member is CodeTypeDestructorDeclaration && method is CodeTypeDestructorDeclaration)
{
return false;
}
if(member is CodeTypeMethodDeclaration
&& (member as CodeTypeMethodDeclaration).Name == method.Name
&& (member as CodeTypeMethodDeclaration).ReturnType != null
&& method.ReturnType != null
&& (member as CodeTypeMethodDeclaration).ReturnType.TypeName == method.ReturnType.TypeName
&& (member as CodeTypeMethodDeclaration).Parameters.Count == method.Parameters.Count
)
{
if((member as CodeTypeMethodDeclaration).Parameters.Count == 1
&& (member as CodeTypeMethodDeclaration).Parameters[0].Type.TypeName != "System.Boolean")
continue;
return false;
}
if(member is CodeTypeMethodDeclaration
&& (member as CodeTypeMethodDeclaration).MemberInfo == method.MemberInfo)
{
return false;
}
}
return true;
}
private static RuleViolation[] emptyViolationsList = new RuleViolation[0];
private Type[] targetedCodeElements = {typeof(CodeClassDeclaration), typeof(CodeStructDeclaration)};
private static Type[] applicableApplicabilityScopeTypes = {typeof(ClassApplicabilityScope),typeof(StructApplicabilityScope),typeof(FileApplicabilityScope)};
public override Type[] ApplicableApplicabilityScopeTypes
{
get
{
return applicableApplicabilityScopeTypes;
}
}
}
}
|