using System;
using System.Collections;
using AnticipatingMinds.Genesis.KnowledgeManagement;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using AnticipatingMinds.CommonUIControls;
using AnticipatingMinds.Genesis.Effectors;
using AnticipatingMinds.Genesis.Effectors.Utilities;
using System.Xml;
using System.Reflection;
using System.Collections.Specialized;
using AnticipatingMinds.PlatformServices.Configuration;
namespace AnticipatingMinds.KnowledgePack.ErrorHandling{
public class DoNotThrowSpecificExceptionsTemplate : RuleTemplate
{
public DoNotThrowSpecificExceptionsTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("DoNotThrowSpecificExceptionsTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("DoNotThrowSpecificExceptionsTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
return new DoNotThrowSpecificExceptionsRule(ruleId, Id, ruleProperties);
}
public override AnticipatingMinds.CommonUIControls.PropertyPage[] GetRulePropertiesUI(IDictionary ruleProperties)
{
AnticipatingMinds.CommonUIControls.PropertyPage[] pages = new AnticipatingMinds.CommonUIControls.PropertyPage[1];
pages[0] = new InheritancePropertyPage(ruleProperties);
return pages;
}
}
public class DoNotThrowSpecificExceptionsRule : Rule
{
#region Work with RegistryConfiguration
const string CONFIG_UI_ROOT = @"SOFTWARE\Anticipating Minds\DevAdvantage\Appearance\Rules\DoNotThrowSpecificExceptionsTemplate";
private RegistryConfiguration config = new RegistryConfiguration(CONFIG_UI_ROOT, RegistryConfiguration.RegistryTarget.LocalMachine);
// array with class names which user use by correction
private string[] LastUsersAppliedClasses
{
get{return config.GetMultiString("LastUsersAppliedClasses");}
set{
if(Array.IndexOf(config.GetMultiString("LastUsersAppliedClasses"), value) == -1)
config.SetValue("LastUsersAppliedClasses", value);
}
}
#endregion
private class RuleData
{
public bool Flag = false;
/* global variable for use in different method
* in initialize
*/
public RuleViolation CurrentViolation = null;
/* Using for storage current ReferenceExpression
* */
public CodeVariableReferenceExpression CurrentVariableReferenceExpression = null;
public RuleViolationCollection violations = new RuleViolationCollection();
public CodeExpression ThrowExcpression = null;
public CodeClassDeclaration ClassDeclaration = null;
}
#region Rule Property
public new class PropertyName : Rule.PropertyName
{
public const string InheritRecommendationList = "InheritRecommendationList";
}
#endregion
#region InheritRecommendation
private ArrayList InheritRecommendationList
{
get
{
return GetProperty(PropertyName.InheritRecommendationList, ErrorHandling.ErrorHandlingUtils.DefaultInheritRecommendationList("InheritRecommendationList.xml")) as ArrayList;
}
set
{
SetProperty(PropertyName.InheritRecommendationList, value);
}
}
#endregion
internal DoNotThrowSpecificExceptionsRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
public override Type[] TargetedCodeElements
{
get
{
return targetedCodeElements;
}
}
/* 1. find block Throw and analyze it
* 1.1 if in block create object check it on incorect type and create violation
* (method AnalyzeThrowStatement)
* 1.2 Insert in violation current type
* 2.1 if in block variable reference check it VariableDeclaration on incorect type and create violation
* (method AnalyzeThrowStatement)
* 2.2 create violation
* find and insert in violation VariableDeclaration
* find and insert in violation ObjectCreate
* Correct : replace VariableDeclaration and ObjectCreate elements
* and update LastUsersAppliedClasses
*/
public override RuleViolation[] Analyze(object codeElement, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
CodeThrowStatement throwStatement = codeElement as CodeThrowStatement;
if(!IsCodeElementInRuleApplicabilityScope(CodeTypeMemberUtils.GetContainingTypeMember(throwStatement)))
return emptyViolationsList;
RuleData ruleData = new RuleData();
ruleData.ThrowExcpression = throwStatement.ToThrow;
#region Get ClassDeclaration object
CodeElementTrace trace = CodeElementTrace.GetCodeElementTrace(throwStatement);
for(int traceFrameIndex = trace.Trace.Length-1;traceFrameIndex>=0; traceFrameIndex--)
{
if(trace.Trace[traceFrameIndex] is CodeClassDeclaration)
{
CodeClassDeclaration classDeclaration = trace.Trace[traceFrameIndex] as CodeClassDeclaration;
ruleData.ClassDeclaration = classDeclaration;
break;
}
}
#endregion
CodeDomWalker.WalkCodeElement(throwStatement.ToThrow ,new CodeDomWalker.WalkerCallback(AnalyzeThrowStatement), ruleData);
if(ruleData.violations.Count != 0)
return ruleData.violations.ToArray();
else
return emptyViolationsList;
}
private CodeDomWalker.WalkerCallbackReturn AnalyzeThrowStatement(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 CodeObjectCreateExpression && IsThrowParent(codeElement))
{
// if in throw object create check it on incorect type
CodeObjectCreateExpression objectCreateExpression = codeElement as CodeObjectCreateExpression;
#region Block testing simple case : (throw new "IncorectTypeException()")
if(CheckVoilation(objectCreateExpression.CreateType as CodeTypeReference, ruleData))
{
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
#endregion
}
// if element is CodeVariableReferenceExpression check it VariableDeclaration
if(codeElement is CodeVariableReferenceExpression && IsThrowParent(codeElement))
{
CodeVariableReferenceExpression variableReferenceExpression = codeElement as CodeVariableReferenceExpression;
ruleData.CurrentVariableReferenceExpression = variableReferenceExpression;
#region Block testing declaration block
if(CheckVoilation(variableReferenceExpression.VariableDeclaration.DeclarationType as CodeTypeReference, ruleData))
{
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
#endregion
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private bool IsThrowParent(CodeElement codeElement)
{
CodeElement parent = codeElement.Parent;
if(parent is CodeParenthesizedExpression)
{
parent = parent.Parent;
}
if(parent is CodeThrowStatement)
return true;
else return false;
}
private CodeDomWalker.WalkerCallbackReturn AnalyzeVariableDeclarationStatementBlock(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
if(codeElement is CodeBinaryExpression)
{
RuleData ruleData = applicationData as RuleData;
CodeBinaryExpression binary = codeElement as CodeBinaryExpression;
string variableTypeName = "";
if(ruleData.CurrentVariableReferenceExpression.VariableDeclaration.DeclarationType.TypeInfo != null)
variableTypeName = ruleData.CurrentVariableReferenceExpression.VariableDeclaration.DeclarationType.TypeInfo.FullName;
if(binary.LeftOperand is CodeVariableReferenceExpression
&& (binary.LeftOperand as CodeVariableReferenceExpression).VariableDeclaration == ruleData.CurrentVariableReferenceExpression.VariableDeclaration
&& binary.RightOperand is CodeObjectCreateExpression
&& (binary.RightOperand as CodeObjectCreateExpression).CreateType.TypeInfo != null
&& (binary.RightOperand as CodeObjectCreateExpression).CreateType.TypeInfo.FullName == variableTypeName
)
{
ruleData.CurrentViolation.ViolationData["CreateObjectExcpression"] = binary.RightOperand;
return CodeDomWalker.WalkerCallbackReturn.Cancel;
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
// check current type
private bool CheckVoilation(CodeTypeReference typeReference, RuleData ruleData)
{
foreach(InheritRecommendation inheritRecommendation in InheritRecommendationList)
{
if(inheritRecommendation.Directly.Equals("Directly"))
{
string inheritTypeName = Type.GetType(inheritRecommendation.Class).FullName;
if(typeReference.TypeInfo != null && inheritTypeName == typeReference.TypeInfo.FullName)
{
CreateViolation(typeReference, ruleData, inheritRecommendation);
return true;
}
}
else if(inheritRecommendation.Directly.Equals("Indirectly"))
{
if(typeReference.TypeInfo != null && typeReference.GetAssemblyTypeManager().IsTypeSubclassOf(typeReference.TypeInfo.FullName,inheritRecommendation.Class))
{
CreateViolation(typeReference, ruleData, inheritRecommendation);
return true;
}
}
}
return false;
}
private void CreateViolation(CodeTypeReference typeReference, RuleData ruleData, InheritRecommendation inheritRecommendation)
{
RuleViolation violation = new RuleViolation(this, (CodeElement)ruleData.ThrowExcpression);
violation.Description = ResourceManager.GetLocalizedString("DoNotThrowSpecificExceptionsTemplate|Voilation|Description",CodeTypeReferenceUtils.GetShortestTypeNameReference(typeReference, typeReference.TypeName));
violation.ViolationData["CodeTypeReference"] = typeReference;
violation.Severity = RuleViolation.ViolationSeverity.Warning;
violation.ViolationData["DefaultValue"] = "";
violation.ViolationData["CodeClassDeclaration"] = ruleData.ClassDeclaration;
violation.ViolationData["InheritRecommendation"] = inheritRecommendation;
if(typeReference.Parent is CodeObjectCreateExpression)
{
violation.ViolationData["CreateObjectExcpression"] = typeReference.Parent as CodeObjectCreateExpression;
}
if(typeReference.Parent is CodeVariableDeclarationStatement && ruleData.CurrentVariableReferenceExpression != null)
{
ruleData.CurrentViolation = violation;
ruleData.Flag = false;
CodeVariableDeclarationStatement declarationStatement = typeReference.Parent as CodeVariableDeclarationStatement;
foreach(CodeVariableDeclarationMember member in declarationStatement.DeclaredVariables)
{
if(member.Name == ruleData.CurrentVariableReferenceExpression.VariableName && member.Initializer != null && member.Initializer is CodeObjectCreateExpression)
{
CodeObjectCreateExpression objectCreateExpression = member.Initializer as CodeObjectCreateExpression;
violation.ViolationData["CreateObjectExcpression"] = objectCreateExpression;
ruleData.Flag = true;
}
}
if(ruleData.Flag == false)
{
CodeDomWalker.WalkCodeElement( CodeStatementUtils.GetElementStatement(typeReference.Parent.Parent) ,new CodeDomWalker.WalkerCallback(AnalyzeVariableDeclarationStatementBlock), ruleData);
}
}
ArrayList recommendations = inheritRecommendation.Recommendations;
RuleViolationCorrection violationCorrection;
ArrayList correctedClassList = new ArrayList();
if(recommendations != null)
{
foreach(CorrectionRecommendation correction in recommendations)
{
if(IsEnteredTypeExists(correction.Class, typeReference, false))
{
bool isDefault = (correction.Default == "True") ? true : false ;
string shortName = CodeTypeReferenceUtils.GetShortestTypeNameReference(typeReference, correction.Class);
violationCorrection = violation.AddCorrection(String.Format(ResourceManager.GetLocalizedString("DoNotDeriveClassesFromSpecificTypesTemplate|Voilation|Correct"), shortName), isDefault, false);
violationCorrection.CorrectionData["CorrectedClass"] = shortName;
violationCorrection.CorrectionData["CorrectedClassFullName"] = correction.Class;
correctedClassList.Add(correction.Class);
if(isDefault)
{
violation.ViolationData["DefaultValue"] = correction.Class;
}
}
}
}
if(LastUsersAppliedClasses != null && LastUsersAppliedClasses.Length != 0)
{
for(int i =0; i < LastUsersAppliedClasses.Length; i++)
{
if(!correctedClassList.Contains(LastUsersAppliedClasses[i]) && IsEnteredTypeExists(LastUsersAppliedClasses[i], typeReference, false))
{
string shortNameUsed = CodeTypeReferenceUtils.GetShortestTypeNameReference(typeReference, LastUsersAppliedClasses[i]);
violationCorrection = violation.AddCorrection(String.Format(ResourceManager.GetLocalizedString("DoNotDeriveClassesFromSpecificTypesTemplate|Voilation|Correct"), shortNameUsed), false, false);
violationCorrection.CorrectionData["CorrectedClass"] = shortNameUsed;
violationCorrection.CorrectionData["CorrectedClassFullName"] = LastUsersAppliedClasses[i];
}
}
}
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("ErrorHandling|ChangeTo"), false, true);
ruleData.violations.Add(violation);
}
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
try
{
codeEffector.BeginCodeChanges("Changed throw type");
RenamingCorrectionForm renamingCorrectionForm = new RenamingCorrectionForm(requestedCorrections,codeEffector,cancelCorrectionEvent);
renamingCorrectionForm.Text = "Specify exception type to throw";
renamingCorrectionForm.Visible = false;
renamingCorrectionForm.BindViolationCorrectionDataToUI +=new AnticipatingMinds.Genesis.Effectors.Utilities.RenamingCorrectionForm.BindViolationCorrectionDataToUIDelegate(renamingCorrectionForm_PopulateCorrectionData);
renamingCorrectionForm.CorrectViolation += new AnticipatingMinds.Genesis.Effectors.Utilities.RenamingCorrectionForm.CorrectViolationDelegate(renamingCorrectionForm_CorrectViolation);
renamingCorrectionForm.IsCorrectionDataValid += new AnticipatingMinds.Genesis.Effectors.Utilities.RenamingCorrectionForm.IsCorrectionDataValidDelegate(renamingForm_ValidateSuggestedName);
renamingCorrectionForm.ShowCorrectionUI();
codeEffector.CommitCodeChanges();
}
catch(Exception)
{
codeEffector.RollbackCodeChanges();
throw;
}
}
private void renamingCorrectionForm_PopulateCorrectionData(CorrectionForm sender, RuleViolationCorrection violationCorrection,CodeEffector codeEffector)
{
CodeTypeReference typeReference = violationCorrection.Violation.ViolationData["CodeTypeReference"] as CodeTypeReference;
codeEffector.ActivateCodeLocation( typeReference );
InheritRecommendation inheritRecommendation = violationCorrection.Violation.ViolationData["InheritRecommendation"] as InheritRecommendation;
string typeInfoFullName = typeReference.TypeName as string;
RenamingCorrectionForm renamingForm = sender as RenamingCorrectionForm;
renamingForm.violationDescriptionLabel.Text = violationCorrection.Violation.Description;
renamingForm.currentValueTextBox.Text = typeInfoFullName;
string defaultValue = violationCorrection.Violation.ViolationData["DefaultValue"] as string;
if(defaultValue != null && defaultValue.Length > 0)
renamingForm.defaultSuggestionTextBox.Text = defaultValue;
else if(inheritRecommendation.Recommendations.Count > 0)
{
renamingForm.defaultSuggestionTextBox.Text = (inheritRecommendation.Recommendations[0] as CorrectionRecommendation).Class;
}else renamingForm.defaultSuggestionTextBox.Text = "";
renamingForm.sugesstionsListBox.Items.Clear();
ArrayList correctedClassList = new ArrayList();
foreach(CorrectionRecommendation correction in inheritRecommendation.Recommendations)
{
if(IsEnteredTypeExists(correction.Class, typeReference, false))
correctedClassList.Add(correction.Class);
}
if(LastUsersAppliedClasses != null && LastUsersAppliedClasses.Length != 0)
{
for(int i =0; i < LastUsersAppliedClasses.Length; i++)
{
if(!correctedClassList.Contains(LastUsersAppliedClasses[i]) && IsEnteredTypeExists(LastUsersAppliedClasses[i], typeReference, false))
correctedClassList.Add(LastUsersAppliedClasses[i]);
}
}
foreach(object item in correctedClassList)
{
renamingForm.sugesstionsListBox.Items.Add(item as string);
}
}
private void renamingCorrectionForm_CorrectViolation(CorrectionForm sender, RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector,object correctionData)
{
CodeTypeReference targetTypeReference = requestedCorrection.Violation.ViolationData["CodeTypeReference"] as CodeTypeReference;
CodeClassDeclaration classDeclaration = requestedCorrection.Violation.ViolationData["CodeClassDeclaration"] as CodeClassDeclaration;
if(targetTypeReference == null) return;
InheritRecommendation inheritRecommendation = requestedCorrection.Violation.ViolationData["InheritRecommendation"] as InheritRecommendation;
string changeToValue;
string changeToValueFullName;
if(correctionData == null)
{
changeToValue = requestedCorrection.CorrectionData["CorrectedClass"] as string;
changeToValueFullName = requestedCorrection.CorrectionData["CorrectedClassFullName"] as string;
}
else
{
changeToValue = correctionData as String;
changeToValueFullName = changeToValue;
}
CodeObjectCreateExpression objectCreate = requestedCorrection.Violation.ViolationData["CreateObjectExcpression"] as CodeObjectCreateExpression;
changeToValue = CodeTypeReferenceUtils.GetShortestTypeNameReference(classDeclaration, changeToValue);
if(targetTypeReference.Parent is CodeVariableDeclarationStatement)
{
if(objectCreate != null)
{
codeEffector.ChangeCodeElement(objectCreate.CreateType,objectCreate.CreateType.GetType().GetProperty("TypeName"),changeToValue);
}
}
codeEffector.ChangeCodeElement(targetTypeReference,targetTypeReference.GetType().GetProperty("TypeName"),changeToValue);
this.LastUsersAppliedClasses = ErrorHandlingUtils.InsertToRegistry(this.LastUsersAppliedClasses, changeToValueFullName);
requestedCorrection.Violation.IsFixed = true;
}
private bool renamingForm_ValidateSuggestedName(CorrectionForm sender, RuleViolationCorrection violationCorrection,CodeEffector codeEffector, object correctionData)
{
CodeTypeReference typeReference = violationCorrection.Violation.ViolationData["CodeTypeReference"] as CodeTypeReference;
string correctedString = correctionData as string;
if(!IsEnteredTypeExists(correctedString, typeReference, true))
{ return false; }
else{ return true;}
}
private bool IsEnteredTypeExists(string typeName, CodeElement codeElement, bool showMessage)
{
CodeAssemblyTypeManager manager = codeElement.GetAssemblyTypeManager();
if(manager != null)
{
CodeTypeInfo typeInfo = manager.FindType(typeName);
if(typeInfo == null)
{
if(showMessage) System.Windows.Forms.MessageBox.Show(ResourceManager.GetLocalizedString("ErrorHandling|NotExistsType"));
return false;
}
else
{
return true;
}
}
return false;
}
private static RuleViolation[] emptyViolationsList = new RuleViolation[0];
private Type[] targetedCodeElements = {typeof(CodeThrowStatement)};
private static Type[] applicableApplicabilityScopeTypes = {typeof(MethodApplicabilityScope),typeof(PropertyApplicabilityScope),typeof(EventApplicabilityScope),typeof(FileApplicabilityScope)};
public override Type[] ApplicableApplicabilityScopeTypes
{
get
{
return applicableApplicabilityScopeTypes;
}
}
}
}
|