using System;
using System.Diagnostics;
using System.Data;
using System.Reflection;
using System.IO;
using System.Collections;
using AnticipatingMinds.Genesis.CodeDOM;
using AnticipatingMinds.Genesis.CodeDOM.Utilities;
namespace AnticipatingMinds.CodeInsight{
/// <exclude/>
//Allow only Anticipating Minds call methods on this assembly.
[System.Security.Permissions.StrongNameIdentityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand,
PublicKey=
"00240000048000009400000006020000002400005253413100040000010001009D309779C258129573FC313836474C75C4CE9F4" +
"107524FA0B9A6DB2E52754459C5A8946E4CBD5B98ACDB2413C5AFD38C1DF00C9A946713E867237B47F9D9CC473D4A853EACBEAB" +
"799EC0A271B468D4B6D52301A414A7772F05FEBD2BA7D0A2835F0D45E401C3C37F9E7B991D29F07DA88E20BB3839A34A2739AB6" +
"56B5204C8BC")]
public class CodeMeasurements
{
private CodeMeasurements(){}
private static CodeMetric[] metrics = null;
private static object metricsLock = new object();
public static CodeMetric[] Metrics
{
get
{
if(metrics == null)
{
lock(metricsLock)
{
if(metrics == null)
{
ArrayList metricsList = new ArrayList() ;
string[] dllFiles = Directory.GetFiles(CodeInsightConfiguration.GetInstance().MetricsFolder,"*.dll");
foreach(string fileName in dllFiles)
{
try
{
Assembly assembly = Assembly.LoadFrom(fileName);
if(assembly == null)
continue;
foreach(Type type in assembly.GetTypes())
{
if(!type.IsSubclassOf(typeof(CodeMetricsFactory)))
continue;
CodeMetricsFactory metricsFactory = Activator.CreateInstance(type) as CodeMetricsFactory;
foreach(CodeMetric metric in metricsFactory.GetMetrics())
metricsList.Add(metric);
}
}
catch(Exception e)
{
System.Diagnostics.Debug.Assert(false, "AnticipatingMinds.CodeInsight", e.ToString());
//Do nothing - if file is not assembly or somehow else
//damaged
}
}
metrics = metricsList.ToArray(typeof(CodeMetric)) as CodeMetric[];
}
}
}
return metrics;
}
}
public static MeasurementDataSet GetCodeMeasurements(CodeSolution solution,CodeMetric[] metrics)
{
MeasurementDataSet dataSet = new MeasurementDataSet();
dataSet.EnforceConstraints = false;
ExtendDataSetSchemaWithMetrics(dataSet,metrics);
PopulateSolutions(dataSet,solution);
ExtendDataSetSchemaWithAggregateMetrics(dataSet,metrics);
dataSet.EnforceConstraints = true;
return dataSet;
}
private static void PopulateSolutions(MeasurementDataSet dataSet,CodeSolution solution)
{
MeasurementDataSet.CodeSolutionRow row = dataSet.CodeSolution.AddCodeSolutionRow(solution.Name);
foreach(DataColumn column in dataSet.CodeSolution.Columns)
if(column is CodeMetricColumn)
row[column] = ((column as CodeMetricColumn).Metric as SolutionMetric).GetValue(solution);
PopulateAssemblies(dataSet,solution,row);
}
private static void PopulateAssemblies(MeasurementDataSet dataSet,CodeSolution solution,MeasurementDataSet.CodeSolutionRow solutionRow)
{
dataSet.Assembly.BeginLoadData();
foreach(CodeAssembly assembly in solution.Assemblies)
{
MeasurementDataSet.AssemblyRow row = dataSet.Assembly.AddAssemblyRow(solutionRow,assembly.AssemblyName,assembly.AssemblyFileName);
foreach(DataColumn column in dataSet.Assembly.Columns)
if(column is CodeMetricColumn)
row[column] = ((column as CodeMetricColumn).Metric as AssemblyMetric).GetValue(assembly);
PopulateAssemblyFiles(dataSet,assembly,row);
PopulateTypes(dataSet,assembly,row);
}
dataSet.Assembly.EndLoadData();
}
private static void PopulateAssemblyFiles(MeasurementDataSet dataSet,CodeAssembly assembly,MeasurementDataSet.AssemblyRow assemblyRow)
{
dataSet.AssemblyFile.BeginLoadData();
foreach(CodeAssemblyFile assemblyFile in assembly.AssemblyFiles)
{
MeasurementDataSet.AssemblyFileRow row = dataSet.AssemblyFile.AddAssemblyFileRow(
assemblyRow,
assemblyFile.SourceFileName);
foreach(DataColumn column in dataSet.AssemblyFile.Columns)
if(column is CodeMetricColumn)
row[column] = ((column as CodeMetricColumn).Metric as AssemblyFileMetric).GetValue(assemblyFile);
}
dataSet.AssemblyFile.EndLoadData();
}
private static void PopulateTypes(MeasurementDataSet dataSet,CodeAssembly assembly,MeasurementDataSet.AssemblyRow assemblyRow)
{
ArrayList assemblyDeclaredTypes = new ArrayList();
foreach(CodeAssemblyFile assemblyFile in assembly.AssemblyFiles)
CodeDomWalker.WalkCompileUnit(assemblyFile,new CodeDomWalker.WalkerCallback(GetAssemblyDeclaredTypes),assemblyDeclaredTypes);
dataSet.TypeDeclaration.BeginLoadData();
foreach(CodeTypeDeclaration typeDeclaration in assemblyDeclaredTypes)
{
MeasurementDataSet.TypeDeclarationRow row = dataSet.TypeDeclaration.AddTypeDeclarationRow(
assemblyRow,
typeDeclaration.FullName,
typeDeclaration.SourcePosition.FileName,
typeDeclaration.SourcePosition.Line,
typeDeclaration.SourcePosition.Column);
foreach(DataColumn column in dataSet.TypeDeclaration.Columns)
if(column is CodeMetricColumn)
row[column] = ((column as CodeMetricColumn).Metric as TypeDeclarationMetric).GetValue(typeDeclaration);
PopulateTypeMembers(dataSet,typeDeclaration,row);
}
dataSet.TypeDeclaration.EndLoadData();
}
private static void PopulateTypeMembers(MeasurementDataSet dataSet,CodeTypeDeclaration typeDeclaration,MeasurementDataSet.TypeDeclarationRow typeDeclarationRow)
{
dataSet.TypeMemberDeclaration.BeginLoadData();
foreach(CodeTypeMemberDeclaration typeMember in CodeTypeDeclarationUtils.GetTypeMembers(typeDeclaration))
{
MeasurementDataSet.TypeMemberDeclarationRow row = dataSet.TypeMemberDeclaration.AddTypeMemberDeclarationRow(
typeDeclarationRow,
GetTypeMemberName(typeMember),
typeMember.SourcePosition.FileName,
typeMember.SourcePosition.Line,
typeMember.SourcePosition.Column);
foreach(DataColumn column in dataSet.TypeMemberDeclaration.Columns)
if(column is CodeMetricColumn)
row[column] = ((column as CodeMetricColumn).Metric as TypeMemberDeclarationMetric).GetValue(typeMember);
PopulateStatements(dataSet,typeMember,row);
}
dataSet.TypeMemberDeclaration.EndLoadData();
}
private static void PopulateStatements(MeasurementDataSet dataSet,CodeTypeMemberDeclaration typeMemberDeclaration,MeasurementDataSet.TypeMemberDeclarationRow typeMemberDeclarationRow)
{
if(!(dataSet.CodeStatement.Columns[dataSet.CodeStatement.Columns.Count-1] is CodeMetricColumn))
return;
ArrayList memberStatements = new ArrayList();
CodeDomWalker.WalkCodeElement(typeMemberDeclaration,new CodeDomWalker.WalkerCallback(GetTypeMemberStatements),memberStatements);
dataSet.CodeStatement.BeginLoadData();
foreach(CodeStatement statement in memberStatements)
{
MeasurementDataSet.CodeStatementRow row = dataSet.CodeStatement.AddCodeStatementRow(
typeMemberDeclarationRow,
statement.SourcePosition.FileName,
statement.SourcePosition.Line,
statement.SourcePosition.Column);
foreach(DataColumn column in dataSet.CodeStatement.Columns)
if(column is CodeMetricColumn)
row[column] = ((column as CodeMetricColumn).Metric as CodeStatementMetric).GetValue(statement);
}
dataSet.CodeStatement.EndLoadData();
}
private static string GetTypeMemberName(CodeTypeMemberDeclaration typeMemberDeclaration)
{
if(typeMemberDeclaration is CodeTypeConstructorDeclaration)
return typeMemberDeclaration.DeclaringType.Name;
if(typeMemberDeclaration is CodeTypeEventListDeclaration)
{
string declaredEvents = "";
foreach(CodeVariableDeclarationMember field in (typeMemberDeclaration as CodeTypeEventListDeclaration).DeclaredEvents)
declaredEvents += ("," + field.Name);
return declaredEvents.Trim(',');
}
if(typeMemberDeclaration is CodeTypeFieldDeclaration)
{
string declaredFields = "";
foreach(CodeVariableDeclarationMember field in (typeMemberDeclaration as CodeTypeFieldDeclaration).DeclaredFields)
declaredFields += ("," + field.Name);
return declaredFields.Trim(',');
}
if(typeMemberDeclaration is CodeTypeMethodDeclaration)
{
return (typeMemberDeclaration as CodeTypeMethodDeclaration).Name;
}
if(typeMemberDeclaration is CodeTypePropertyDeclaration)
{
return (typeMemberDeclaration as CodeTypePropertyDeclaration).Name;
}
if(typeMemberDeclaration is CodeTypeEventDeclaration)
{
return (typeMemberDeclaration as CodeTypeEventDeclaration).Name;
}
Debug.Assert(false,"Add ocde to get type member name");
return string.Empty;
}
private static void AddAggregatedColumns(DataTable baseTable,CodeMetric baseMetric)
{
foreach(CodeAggregateMetric aggregateMetric in baseMetric.GetAggregateMetrics())
{
string expressionFormat = "";
switch(aggregateMetric.AggregationType)
{
case MetricAggregationType.Average:
{
expressionFormat = "AVG(Child([{0}]).[{1}])";
break;
}
case MetricAggregationType.Max:
{
expressionFormat = "MAX(Child([{0}]).[{1}])";
break;
}
case MetricAggregationType.Min:
{
expressionFormat = "MIN(Child([{0}]).[{1}])";
break;
}
case MetricAggregationType.Sum:
{
expressionFormat = "SUM(Child([{0}]).[{1}])";
break;
}
default:
{
Debug.Assert(false,"Add aggregation function");
break;
}
}
ArrayList relationships = new ArrayList();
foreach(DataRelation dataRelation in baseTable.ParentRelations)
relationships.Add(dataRelation);
while(relationships.Count != 0)
{
DataRelation dataRelation = relationships[0] as DataRelation;
if(dataRelation.ParentTable is MeasurementDataSet.CodeSolutionDataTable &&
(aggregateMetric.AggregationLevels & MetricAggregationLevel.CodeSolution) == 0)
{
break;
}
if(dataRelation.ParentTable is MeasurementDataSet.AssemblyDataTable &&
(aggregateMetric.AggregationLevels & MetricAggregationLevel.Assembly) == 0)
{
break;
}
if(dataRelation.ParentTable is MeasurementDataSet.TypeDeclarationDataTable &&
(aggregateMetric.AggregationLevels & MetricAggregationLevel.TypeDeclaration) == 0)
{
break;
}
if(dataRelation.ParentTable is MeasurementDataSet.TypeMemberDeclarationDataTable &&
(aggregateMetric.AggregationLevels & MetricAggregationLevel.TypeMemberDeclaration) == 0)
{
break;
}
string expression = String.Format(expressionFormat,dataRelation.RelationName,dataRelation.ChildTable == baseTable ? baseMetric.Id:aggregateMetric.Id);
DataColumn column = new DataColumn(aggregateMetric.Id,typeof(decimal),expression);
dataRelation.ParentTable.Columns.Add(column);
relationships.RemoveAt(0);
foreach(DataRelation r in dataRelation.ParentTable.ParentRelations)
relationships.Add(r);
}
}
}
private static void ExtendDataSetSchemaWithAggregateMetrics(MeasurementDataSet dataSet,CodeMetric[] metrics)
{
foreach(CodeMetric metric in metrics)
{
if(metric is SolutionMetric)
{
AddAggregatedColumns(dataSet.CodeSolution,metric);
continue;
}
if(metric is AssemblyMetric)
{
AddAggregatedColumns(dataSet.Assembly,metric);
continue;
}
if(metric is AssemblyFileMetric)
{
AddAggregatedColumns(dataSet.AssemblyFile,metric);
continue;
}
if(metric is TypeDeclarationMetric)
{
AddAggregatedColumns(dataSet.TypeDeclaration,metric);
continue;
}
if(metric is TypeMemberDeclarationMetric)
{
AddAggregatedColumns(dataSet.TypeMemberDeclaration,metric);
continue;
}
if(metric is CodeStatementMetric)
{
AddAggregatedColumns(dataSet.CodeStatement,metric);
continue;
}
}
}
private static void ExtendDataSetSchemaWithMetrics(MeasurementDataSet dataSet,CodeMetric[] metrics)
{
foreach(CodeMetric metric in metrics)
{
if(metric is SolutionMetric)
{
dataSet.CodeSolution.Columns.Add(new CodeMetricColumn(metric));
dataSet.Metric.AddMetricRow(metric.Id,metric.Name,metric.Description,"SolutionMetric",uint.MaxValue);
foreach(CodeAggregateMetric aggregateMetric in metric.GetAggregateMetrics())
dataSet.Metric.AddMetricRow(aggregateMetric.Id,aggregateMetric.Name,aggregateMetric.Description,"AggregateSolutionMetric",(uint)aggregateMetric.AggregationLevels);
continue;
}
if(metric is AssemblyMetric)
{
dataSet.Assembly.Columns.Add(new CodeMetricColumn(metric));
dataSet.Metric.AddMetricRow(metric.Id,metric.Name,metric.Description,"AssemblyMetric",uint.MaxValue);
foreach(CodeAggregateMetric aggregateMetric in metric.GetAggregateMetrics())
dataSet.Metric.AddMetricRow(aggregateMetric.Id,aggregateMetric.Name,aggregateMetric.Description,"AggregateAssemblyMetric",(uint)aggregateMetric.AggregationLevels);
continue;
}
if(metric is AssemblyFileMetric)
{
dataSet.AssemblyFile.Columns.Add(new CodeMetricColumn(metric));
dataSet.Metric.AddMetricRow(metric.Id,metric.Name,metric.Description,"AssemblyFileMetric",uint.MaxValue);
foreach(CodeAggregateMetric aggregateMetric in metric.GetAggregateMetrics())
dataSet.Metric.AddMetricRow(aggregateMetric.Id,aggregateMetric.Name,aggregateMetric.Description,"AggregateAssemblyFileMetric",(uint)aggregateMetric.AggregationLevels);
continue;
}
if(metric is TypeDeclarationMetric)
{
dataSet.TypeDeclaration.Columns.Add(new CodeMetricColumn(metric));
dataSet.Metric.AddMetricRow(metric.Id,metric.Name,metric.Description,"TypeDeclarationMetric",uint.MaxValue);
foreach(CodeAggregateMetric aggregateMetric in metric.GetAggregateMetrics())
dataSet.Metric.AddMetricRow(aggregateMetric.Id,aggregateMetric.Name,aggregateMetric.Description,"AggregateTypeDeclarationMetric",(uint)aggregateMetric.AggregationLevels);
continue;
}
if(metric is TypeMemberDeclarationMetric)
{
dataSet.TypeMemberDeclaration.Columns.Add(new CodeMetricColumn(metric));
dataSet.Metric.AddMetricRow(metric.Id,metric.Name,metric.Description,"TypeMemberDeclarationMetric",uint.MaxValue);
foreach(CodeAggregateMetric aggregateMetric in metric.GetAggregateMetrics())
dataSet.Metric.AddMetricRow(aggregateMetric.Id,aggregateMetric.Name,aggregateMetric.Description,"AggregateTypeMemberDeclarationMetric",(uint)aggregateMetric.AggregationLevels);
continue;
}
if(metric is CodeStatementMetric)
{
dataSet.CodeStatement.Columns.Add(new CodeMetricColumn(metric));
dataSet.Metric.AddMetricRow(metric.Id,metric.Name,metric.Description,"CodeStatementMetric",int.MaxValue);
foreach(CodeAggregateMetric aggregateMetric in metric.GetAggregateMetrics())
dataSet.Metric.AddMetricRow(aggregateMetric.Id,aggregateMetric.Name,aggregateMetric.Description,"AggregateCodeStatementMetric",(uint)aggregateMetric.AggregationLevels);
continue;
}
}
}
private static CodeDomWalker.WalkerCallbackReturn GetAssemblyDeclaredTypes(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
switch(notificationType)
{
case CodeDomWalker.CallBackNotificationType.OnElement:
{
if(codeElement is CodeTypeDeclaration)
{
(applicationData as ArrayList).Add(codeElement);
}
break;
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
private static CodeDomWalker.WalkerCallbackReturn GetTypeMemberStatements(CodeElement codeElement, CodeDomWalker.CallBackNotificationType notificationType, CodeDomWalkerContext walkerContext,object applicationData)
{
switch(notificationType)
{
case CodeDomWalker.CallBackNotificationType.OnElement:
{
if(codeElement is CodeStatement)
{
(applicationData as ArrayList).Add(codeElement);
}
break;
}
}
return CodeDomWalker.WalkerCallbackReturn.Next;
}
}
}
|