using System;
using System.Collections;
using AnticipatingMinds.Genesis.KnowledgeManagement;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.PlatformServices.Configuration;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
namespace AnticipatingMinds.KnowledgePack.Design{
public class MethodComplexityExceededRuleTemplate : RuleTemplate
{
public MethodComplexityExceededRuleTemplate(string templateId, IDictionary templateProperties):base(templateId,templateProperties)
{
}
public override string Name
{
get
{
return ResourceManager.GetLocalizedString("MethodComplexityExceededRuleTemplate|Name");
}
}
public override string Description
{
get
{
return ResourceManager.GetLocalizedString("MethodComplexityExceededRuleTemplate|Description");
}
}
public override Rule CreateRule(string ruleId, IDictionary ruleProperties)
{
return new MethodComplexityExceededRuleRule(ruleId, Id, ruleProperties);
}
public override AnticipatingMinds.CommonUIControls.PropertyPage[] GetRulePropertiesUI(IDictionary ruleProperties)
{
AnticipatingMinds.CommonUIControls.PropertyPage[] pages = new AnticipatingMinds.CommonUIControls.PropertyPage[1];
pages[0] = new MethodComplexityExceededPropertyPage(ruleProperties);
return pages;
}
}
public class MethodComplexityExceededRuleRule : Rule
{
const string CONFIG_UI_ROOT = @"SOFTWARE\Anticipating Minds\DevAdvantage\Appearance\Rules\MethodElementMetricsExceededRuleTemplate";
private RegistryConfiguration config = new RegistryConfiguration(CONFIG_UI_ROOT, RegistryConfiguration.RegistryTarget.LocalMachine);
private int GetValueMetricClass(string metricType)
{
MetricClasses metricClasses;
switch(metricType)
{
case "Cyclomatic":
metricClasses = new CyclomaticClass(this.RuleMetricDefaultValue, this.Name);
break;
case "CyclomaticDensity":
metricClasses = new CyclomaticDensityMetricClass(this.RuleMetricDefaultValue, this.Name);
break;
default:
metricClasses = new CyclomaticClass(this.RuleMetricDefaultValue, this.Name);
break;
}
return metricClasses.Value;
}
#region Rule Property
public new class PropertyName : Rule.PropertyName
{
public const string IncludeLoopStatements = "IncludeLoopStatements";
public const string IncludeSwitchStatements = "IncludeSwitchStatements";
public const string CurrentMetricsType = "CurrentMetricsType";
public const string MetricDefaultValue = "MetricDefaultValue";
}
public MetricDefaultValue RuleMetricDefaultValue
{
get
{
return GetProperty("MetricDefaultValue", new MetricDefaultValue()) as MetricDefaultValue;
}
set{
SetProperty("MetricDefaultValue", value);
}
}
public string CurrentMetricsType
{
get{ return GetProperty(PropertyName.CurrentMetricsType, "Cyclomatic").ToString();}
set{ SetProperty(PropertyName.CurrentMetricsType, value);}
}
public bool IncludeLoopStatements
{
get{ return Convert.ToBoolean(GetProperty(PropertyName.IncludeLoopStatements, true));}
set{ SetProperty(PropertyName.IncludeLoopStatements, value);}
}
public bool IncludeSwitchStatements
{
get{ return Convert.ToBoolean(GetProperty(PropertyName.IncludeSwitchStatements, true));}
set{ SetProperty(PropertyName.IncludeSwitchStatements, value);}
}
#endregion
internal MethodComplexityExceededRuleRule(string id, string templateId, IDictionary ruleProperties) : base(id,templateId,ruleProperties)
{
}
public override Type[] TargetedCodeElements
{
get
{
return targetedCodeElements;
}
}
private class RuleData
{
public RuleViolationCollection violations = new RuleViolationCollection();
public int MemberCyclomaticValue = 0;
public int MemberCyclomaticDensityValue = 0;
}
public override RuleViolation[] Analyze(object codeElement, System.Threading.ManualResetEvent cancelAnalysisEvent)
{
CodeTypeMemberDeclaration member = codeElement as CodeTypeMemberDeclaration;
if(member == null) return emptyViolationsList;
if(!IsCodeElementInRuleApplicabilityScope(CodeTypeMemberUtils.GetContainingTypeMember(member)))
return emptyViolationsList;
string memberName = MethodElementMetricsExceededRuleUtils.GetMemberName(member);
RuleData ruleData = new RuleData();
if(member is CodeTypeMethodDeclaration)
{
AnalizeMemberStatements(ruleData, (member as CodeTypeMethodDeclaration).Statements, memberName);
}
else if(member is CodeTypePropertyDeclaration)
{
AnalizeMemberStatements(ruleData, (member as CodeTypePropertyDeclaration).SetAccessorStatements, memberName);
AnalizeMemberStatements(ruleData, (member as CodeTypePropertyDeclaration).GetAccessorStatements, memberName);
}
else if(member is CodeTypeEventDeclaration)
{
AnalizeMemberStatements(ruleData, (member as CodeTypeEventDeclaration).RemoveAccessorStatements, memberName);
AnalizeMemberStatements(ruleData, (member as CodeTypeEventDeclaration).AddAccessorStatements, memberName);
}
else if(member is CodeTypeIndexerDeclaration)
{
AnalizeMemberStatements(ruleData, (member as CodeTypeIndexerDeclaration).SetAccessorStatements, memberName);
AnalizeMemberStatements(ruleData, (member as CodeTypeIndexerDeclaration).GetAccessorStatements, memberName);
}
if(ruleData.violations.Count != 0)
return ruleData.violations.ToArray();
else
return emptyViolationsList;
}
private void AnalizeMemberStatements(RuleData ruleData, CodeElement codeElement, string memberName)
{
ruleData.MemberCyclomaticDensityValue = 0;
ruleData.MemberCyclomaticValue = 0;
CodeDomWalker.WalkCodeElement(codeElement ,new CodeDomWalker.WalkerCallback(AnalyzeMemberDeclaration), ruleData);
if(this.CurrentMetricsType == "Cyclomatic")
{
if(ruleData.MemberCyclomaticValue > GetValueMetricClass("Cyclomatic"))
{
RuleViolation violation = new RuleViolation(this, codeElement);
violation.Description = ResourceManager.GetLocalizedString("MethodComplexityExceededRuleRule|Cyclomatic|Description", memberName, ruleData.MemberCyclomaticValue.ToString(), GetValueMetricClass("Cyclomatic").ToString());
violation.Severity = RuleViolation.ViolationSeverity.Suggestion;
ruleData.violations.Add(violation);
}
}else if(this.CurrentMetricsType == "CyclomaticDensity"){
double cyclomaticDensity = (ruleData.MemberCyclomaticDensityValue == 0)? 0 : Convert.ToDouble(ruleData.MemberCyclomaticValue) / ruleData.MemberCyclomaticDensityValue;
cyclomaticDensity = Math.Round(cyclomaticDensity, 1);
if(cyclomaticDensity > GetValueMetricClass("CyclomaticDensity"))
{
RuleViolation violation = new RuleViolation(this, codeElement);
violation.Description = ResourceManager.GetLocalizedString("MethodComplexityExceededRuleRule|CyclomaticDensity|Description",memberName, cyclomaticDensity.ToString(), GetValueMetricClass("CyclomaticDensity").ToString());
violation.Severity = RuleViolation.ViolationSeverity.Suggestion;
ruleData.violations.Add(violation);
}
}
}
public CodeDomWalker.WalkerCallbackReturn AnalyzeMemberDeclaration(CodeElement codeElement,CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
if(notificationType != CodeDomWalker.CallBackNotificationType.OnElement)
{
return CodeDomWalker.WalkerCallbackReturn.Next;
}
RuleData ruleData = applicationData as RuleData;
ruleData.MemberCyclomaticValue += EvaluateCodeComplexity( codeElement );
ruleData.MemberCyclomaticDensityValue += EvaluateCodeStatement( codeElement );
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private int EvaluateCodeStatement( CodeElement codeElement )
{
int statementIncrease = 0;
// Logical blocks (if and switch)
if ( codeElement is CodeIfStatement )
{
statementIncrease++;
}
else if ( codeElement is CodeSwitchStatement && this.IncludeSwitchStatements)
{
statementIncrease++;
}
else if ( codeElement is CodeConditionalExpression )
{
statementIncrease++;
}
// conditional loops
else if ( codeElement is CodeWhileStatement && this.IncludeLoopStatements)
{
statementIncrease++;
}
else if ( codeElement is CodeDoStatement && this.IncludeLoopStatements)
{
statementIncrease++;
}
else if ( codeElement is CodeForEachStatement && this.IncludeLoopStatements)
{
statementIncrease++;
}
else if ( codeElement is CodeForStatement && this.IncludeLoopStatements)
{
statementIncrease++;
}
// Jump statements
else if ( codeElement is CodeGotoStatement )
{
statementIncrease++;
}
else if ( codeElement is CodeReturnStatement )
{
statementIncrease++;
}
else if ( codeElement is CodeContinueStatement )
{
statementIncrease++;
}
else if ( codeElement is CodeThrowStatement )
{
statementIncrease++;
}
else if ( codeElement is CodeSwitchGotoStatement )
{
statementIncrease++;
}
else if ( codeElement is CodeBreakStatement
&& !(codeElement.Parent is CodeSwitchStatement)
&& !(codeElement.Parent is CodeSwitchCase))
{
statementIncrease++;
}
// And catch blocks
else if ( codeElement is CodeTryStatement )
{
statementIncrease++;
}
return statementIncrease;
}
private int EvaluateCodeComplexity( CodeElement codeElement )
{
int comlexityIncrease = 0;
// Logical blocks (if and switch)
if ( codeElement is CodeIfStatement )
{
comlexityIncrease++;
CodeIfStatement ifStatement = codeElement as CodeIfStatement;
if ( ifStatement.FalseStatement != null ) comlexityIncrease++;
}
else if ( codeElement is CodeSwitchStatement && this.IncludeSwitchStatements)
{
// Must get each case in the collection, + defailt if exists
CodeSwitchStatement switchStatement = codeElement as CodeSwitchStatement;
comlexityIncrease += switchStatement.Cases.Count;
if ( switchStatement.DefaultCaseStatements != null ) comlexityIncrease++;
}
else if ( codeElement is CodeConditionalExpression )
{
comlexityIncrease += 2;
}
// conditional loops
else if ( codeElement is CodeWhileStatement && this.IncludeLoopStatements)
{
comlexityIncrease++;
}
else if ( codeElement is CodeDoStatement && this.IncludeLoopStatements)
{
comlexityIncrease++;
}
else if ( codeElement is CodeForEachStatement && this.IncludeLoopStatements)
{
comlexityIncrease++;
}
else if ( codeElement is CodeForStatement && this.IncludeLoopStatements)
{
comlexityIncrease++;
}
// Jump statements
else if ( codeElement is CodeGotoStatement )
{
comlexityIncrease++;
}
else if ( codeElement is CodeReturnStatement )
{
// TODO: Should be more intelligent. if only one return statements
// and it is at the end, then may not really add complexity
comlexityIncrease++;
}
else if ( codeElement is CodeContinueStatement )
{
comlexityIncrease++;
}
else if ( codeElement is CodeThrowStatement )
{
comlexityIncrease++;
}
else if ( codeElement is CodeSwitchGotoStatement )
{
comlexityIncrease++;
}
else if ( codeElement is CodeBreakStatement
&& !(codeElement.Parent is CodeSwitchStatement)
&& !(codeElement.Parent is CodeSwitchCase))
{
comlexityIncrease++;
}
// And catch blocks
else if ( codeElement is CodeTryStatement )
{
// Must get each catch block, + finally
CodeTryStatement tryStatement = codeElement as CodeTryStatement;
comlexityIncrease += tryStatement.CatchClauses.Count;
if ( tryStatement.FinallyClause != null ) comlexityIncrease++;
}
return comlexityIncrease;
}
public override void Correct(RuleViolationCorrection[] requestedCorrections, AnticipatingMinds.Genesis.Effectors.CodeEffector codeEffector, System.Threading.ManualResetEvent cancelCorrectionEvent)
{
}
private static RuleViolation[] emptyViolationsList = new RuleViolation[0];
private Type[] targetedCodeElements = {typeof(CodeTypeMemberDeclaration), typeof(CodeTypeEventDeclaration), typeof(CodeTypePropertyDeclaration)};
private static Type[] applicableApplicabilityScopeTypes = {typeof(MethodApplicabilityScope),typeof(PropertyApplicabilityScope),typeof(EventApplicabilityScope),typeof(TypeMemberApplicabilityScope),typeof(FileApplicabilityScope)};
public override Type[] ApplicableApplicabilityScopeTypes
{
get
{
return applicableApplicabilityScopeTypes;
}
}
}
}
|