using System;
using System.Collections;
using AnticipatingMinds.Genesis.KnowledgeManagement;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.AspNetDom;
using AnticipatingMinds.Genesis.Effectors.Utilities;
using AnticipatingMinds.Genesis.Effectors;
using System.Text.RegularExpressions;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
using System.Windows.Forms;
namespace AnticipatingMinds.KnowledgePack.Design{
public class PublicFieldsShouldBePropertiesRuleTemplate : RuleTemplate
{
public PublicFieldsShouldBePropertiesRuleTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
return new PublicFieldsShouldBePropertiesRuleRule(ruleId, Id, ruleProperties);
}
}
public class PublicFieldsShouldBePropertiesRuleRule : Rule
{
internal PublicFieldsShouldBePropertiesRuleRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
public override Type[] TargetedCodeElements
{
get
{
return targetedCodeElements;
}
}
#region Analize
public override RuleViolation[] Analyze(object codeElement, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
if(!IsCodeElementInRuleApplicabilityScope(codeElement as CodeElement))
return emptyViolationsList;
CodeClassDeclaration classDeclaration = codeElement as CodeClassDeclaration;
//Do not analyze properties inside asp.net files.
if(classDeclaration is AspNetClassDeclaration)
return emptyViolationsList;
RuleViolationCollection violations = new RuleViolationCollection();
foreach(CodeTypeMemberDeclaration member in classDeclaration.Members)
{
CodeTypeFieldDeclaration field = member as CodeTypeFieldDeclaration;
if(field != null)
{
if((field.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public) != 0
&& (field.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Const) == 0
)
{
ArrayList listOfModifiers = getFieldeclarationModifiers(field);
bool readOnly = listOfModifiers.Contains(CodeTypeMemberDeclaration.MemberDeclarationModifiers.ReadOnly);
foreach(CodeVariableDeclarationMember fieldMember in field.DeclaredFields)
{
//find Property assocation to this field
bool existsAssocationProperty = findReferenceToField(classDeclaration, fieldMember);
RuleViolation violation = new RuleViolation(this , (CodeElement) fieldMember);
string modifiers = "Public";
violation.Description = ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleRule|Violation|Description", modifiers, fieldMember.Name, classDeclaration.Name);
violation.Severity = RuleViolation.ViolationSeverity.Suggestion;
violation.ViolationData["CodeClassDeclaration"] = classDeclaration;
violation.ViolationData["CodeTypeFieldDeclaration"] = field;
violation.ViolationData["CodeVariableDeclarationMember"] = fieldMember;
violation.ViolationData["ListOfModifiers"] = listOfModifiers;
violation.ViolationData["existsAssocationProperty"] = existsAssocationProperty;
string propertyName;
string fieldName;
CreatePropertyAndFieldNames(classDeclaration,field,fieldMember,out propertyName,out fieldName);
//Corrections should be ordered in logically in the order of
//more oten to less often correction.
RuleViolationCorrection violationCorrection;
//Add conversion to getter/setter property first
if(!readOnly)
{
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleRule|Violation|RenameProperty", propertyName), false, false);
violationCorrection.CorrectionData["MakeReadOnly"] = false;
violationCorrection.CorrectionData["MakePrivate"] = false;
}
//Add conversion to read only property second
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleRule|Violation|RenameReadonlyProperty", propertyName), false, false);
violationCorrection.CorrectionData["MakeReadOnly"] = true;
violationCorrection.CorrectionData["MakePrivate"] = false;
//and now just add make private.
violationCorrection = violation.AddCorrection(ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleRule|Violation|Private"), false, false);
violationCorrection.CorrectionData["MakeReadOnly"] = false;
violationCorrection.CorrectionData["MakePrivate"] = true;
violations.Add(violation);
}
}
}
}
return violations.ToArray();
}
// check and create right names for property and private field
private void CreatePropertyAndFieldNames(CodeClassDeclaration classDeclaration, CodeTypeFieldDeclaration field, CodeVariableDeclarationMember member,out string propertyName,out string fieldName)
{
propertyName = member.Name;
fieldName = member.Name;
if(Regex.IsMatch(member.Name, "^[A-Z]"))
{
fieldName = member.Name.Trim().Substring(0, 1).ToLower()+ member.Name.Substring(1);
fieldName = checkClassDeclarationToCurrectName(classDeclaration, fieldName);
}
else
{
fieldName = "_"+member.Name;
fieldName = checkClassDeclarationToCurrectName(classDeclaration, fieldName);
}
}
// find suggested name in current type
private string checkClassDeclarationToCurrectName(CodeClassDeclaration classDeclaration, string name)
{
bool findName = false;
if(classDeclaration.GetAssemblyTypeManager().FindEvent(classDeclaration.FullName, name, true) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindEvent(classDeclaration.FullName, name, false) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindField(classDeclaration.FullName, name, true) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindField(classDeclaration.FullName, name, false) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindMethod(classDeclaration.FullName, name, true) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindMethod(classDeclaration.FullName, name, false) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindProperty(classDeclaration.FullName, name, true) != null)
findName = true;
if(classDeclaration.GetAssemblyTypeManager().FindProperty(classDeclaration.FullName, name, false) != null)
findName = true;
if(findName || !CSharpUtils.IsValidCSharpIdentifier(name))
{
return checkClassDeclarationToCurrectName(classDeclaration, "_"+name);
}
else
{
return name;
}
}
// Find reference to current field
private bool findReferenceToField(CodeClassDeclaration classDeclaration, CodeVariableDeclarationMember member)
{
foreach(CodeExpression expression in CodeNamedReferenceExpressionUtils.FindReferenceTo(classDeclaration, member.Name))
{
CodeElementTrace trace = CodeElementTrace.GetCodeElementTrace(expression);
bool returnStatement = false;
bool propertyStatement = false;
/*if code expression include in CodeTypePropertyDeclaration && CodeReturnStatement
* then this property is association with current field
* */
for(int traceIndex = trace.Trace.Length-1; traceIndex >= 0; traceIndex--)
{
if((trace.Trace[traceIndex] as CodeClassDeclaration) != null )
break;
if((trace.Trace[traceIndex] as CodeTypePropertyDeclaration) != null && returnStatement)
{
propertyStatement = true;
break;
}
if((trace.Trace[traceIndex] as CodeReturnStatement) != null )
{
returnStatement = true;
}
}
if(propertyStatement)
return true;
}
return false;
}
// return collection of all field fodifiers
private ArrayList getFieldeclarationModifiers(CodeTypeFieldDeclaration field)
{
ArrayList listModifiers = new ArrayList();
if((field.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public) != 0)
{
listModifiers.Add(CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public);
}
if((field.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Static) != 0)
{
listModifiers.Add(CodeTypeMemberDeclaration.MemberDeclarationModifiers.Static);
}
if((field.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.Volatile) != 0)
{
listModifiers.Add(CodeTypeMemberDeclaration.MemberDeclarationModifiers.Volatile);
}
if((field.Modifiers & CodeTypeMemberDeclaration.MemberDeclarationModifiers.ReadOnly) != 0)
{
listModifiers.Add(CodeTypeMemberDeclaration.MemberDeclarationModifiers.ReadOnly);
}
return listModifiers;
}
#endregion
#region Correct
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
try
{
codeEffector.BeginCodeChanges("");
RenamingCorrectionForm renamingCorrectionForm = new RenamingCorrectionForm(requestedCorrections,codeEffector,cancelCorrectionEvent);
renamingCorrectionForm.Text = "";
renamingCorrectionForm.Visible = false;
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 bool renamingForm_ValidateSuggestedName(CorrectionForm sender, RuleViolationCorrection violationCorrection,CodeEffector codeEffector, object correctionData)
{
string suggestedName = correctionData as string;
CodeClassDeclaration classDeclaration = violationCorrection.Violation.ViolationData["CodeClassDeclaration"] as CodeClassDeclaration;
if(!CSharpUtils.IsValidCSharpIdentifier(suggestedName as string))
{
MessageBox.Show(ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleRule|SuggestedValue", suggestedName), "", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
if(suggestedName != checkClassDeclarationToCurrectName(classDeclaration, suggestedName))
{
MessageBox.Show(ResourceManager.GetLocalizedString("PublicFieldsShouldBePropertiesRuleRule|NameExists", suggestedName), "", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
return true;
}
private void renamingCorrectionForm_CorrectViolation(CorrectionForm sender, RuleViolationCorrection requestedCorrection, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector,object correctionData)
{
CodeClassDeclaration classDeclaration = requestedCorrection.Violation.ViolationData["CodeClassDeclaration"] as CodeClassDeclaration;
CodeVariableDeclarationMember member = requestedCorrection.Violation.ViolationData["CodeVariableDeclarationMember"] as CodeVariableDeclarationMember;
CodeTypeFieldDeclaration field = requestedCorrection.Violation.ViolationData["CodeTypeFieldDeclaration"] as CodeTypeFieldDeclaration;
ArrayList listOfModifiers = requestedCorrection.Violation.ViolationData["ListOfModifiers"] as ArrayList;
string propertyName;
string fieldName;
CreatePropertyAndFieldNames(classDeclaration,field,member,out propertyName,out fieldName);
bool makePrivate = Convert.ToBoolean(requestedCorrection.CorrectionData["MakePrivate"]);
if( makePrivate)
{
field.Modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public;
field.Modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.New;
field.Modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Private;
codeEffector.ChangeCodeElement(field, field.GetType().GetProperty("Modifiers"), field.Modifiers);
}
else
{
CodeTypeMemberDeclarationCollection tc = new CodeTypeMemberDeclarationCollection();
int index = classDeclaration.Members.IndexOf(field);
if(field.DeclaredFields.Count > 1)
{
codeEffector.DeleteCodeElement(member);
tc.Add(createPropertyDeclaration(field, member, propertyName, listOfModifiers, fieldName, Convert.ToBoolean(requestedCorrection.CorrectionData["MakeReadOnly"])));
}
else
{
codeEffector.ReplaceCodeElement(field, createPropertyDeclaration(field, member, propertyName, listOfModifiers, fieldName, Convert.ToBoolean(requestedCorrection.CorrectionData["MakeReadOnly"])));
}
tc.Add(createFieldDeclaration(field, member, fieldName));
codeEffector.PerformCodeChanges();
codeEffector.AddCodeElements(tc, classDeclaration, classDeclaration.Members, index);
}
requestedCorrection.Violation.IsFixed = true;
}
private CodeTypeFieldDeclaration createFieldDeclaration(CodeTypeFieldDeclaration field, CodeVariableDeclarationMember member, string fieldName)
{
CodeTypeFieldDeclaration fieldDeclaration = new CodeTypeFieldDeclaration();
CodeVariableDeclarationMember variableDeclaration = new CodeVariableDeclarationMember();
variableDeclaration.Name = fieldName;
if(member.Initializer != null)
{
variableDeclaration.Initializer = member.Initializer;
}
fieldDeclaration.Attributes.AddRange( field.Attributes.Clone() as CodeAttributeCollection);
fieldDeclaration.DeclaredFields.Add(variableDeclaration);
fieldDeclaration.DeclarationType = field.DeclarationType;
// set modifier to propertyDeclaration
fieldDeclaration.Modifiers = field.Modifiers;
fieldDeclaration.Modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.Public;
fieldDeclaration.Modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.New;
fieldDeclaration.Modifiers |= CodeTypeMemberDeclaration.MemberDeclarationModifiers.Private;
return fieldDeclaration;
}
private CodeTypePropertyDeclaration createPropertyDeclaration(CodeTypeFieldDeclaration field, CodeVariableDeclarationMember member, string propertyName, ArrayList listOfModifiers, string fieldName, bool makeReadOnly)
{
CodeTypePropertyDeclaration propertyDeclaration = new CodeTypePropertyDeclaration();
propertyDeclaration.Name = propertyName;
propertyDeclaration.ReturnType = field.DeclarationType;
// set modifier to propertyDeclaration
propertyDeclaration.Modifiers = field.Modifiers;
propertyDeclaration.Modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.Volatile;
propertyDeclaration.Modifiers &= ~CodeTypeMemberDeclaration.MemberDeclarationModifiers.ReadOnly;
#region Create Get Statement
CodeStatementBlock getBlock = new CodeStatementBlock();
CodeReturnStatement returnStatement = new CodeReturnStatement();
CodeFieldReferenceExpression fieldReferenceExpressionGet = new CodeFieldReferenceExpression(null, fieldName);
returnStatement.Expression = fieldReferenceExpressionGet;
getBlock.Statements.Add(returnStatement);
#endregion
CodeStatementBlock setBlock = null;
if(!makeReadOnly)
{
#region Create Set Statement
setBlock = new CodeStatementBlock();
CodeFieldReferenceExpression fieldReferenceExpressionSet = new CodeFieldReferenceExpression(null, fieldName);
CodeMethodParameterReferenceExpression valueExpression = new CodeMethodParameterReferenceExpression();
valueExpression.MethodParameter = new CodeMethodParameter(null, "value");
CodeBinaryExpression binaryExpression = new CodeBinaryExpression();
binaryExpression.Operator = CodeBinaryOperatorType.Assign;
binaryExpression.LeftOperand = fieldReferenceExpressionSet;
binaryExpression.RightOperand = valueExpression;
CodeExpressionStatement setStatement = new CodeExpressionStatement();
setStatement.Expression = binaryExpression;
setBlock.Statements.Add(setStatement);
#endregion
}
propertyDeclaration.GetAccessorStatements = getBlock;
if(setBlock != null)
propertyDeclaration.SetAccessorStatements = setBlock;
return propertyDeclaration;
}
#endregion
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;
}
}
}
}
|