diff --git a/src/AddIns/Analysis/CodeQuality/Src/Field.cs b/src/AddIns/Analysis/CodeQuality/Src/Field.cs
index d07e93b5a4..e0a8b40035 100644
--- a/src/AddIns/Analysis/CodeQuality/Src/Field.cs
+++ b/src/AddIns/Analysis/CodeQuality/Src/Field.cs
@@ -58,6 +58,16 @@ namespace ICSharpCode.CodeQualityAnalysis
///
public bool IsReadOnly { get; set; }
+ ///
+ /// Whether the type of field is generic
+ ///
+ public bool IsGenericInstance { get; set; }
+
+ ///
+ /// If the field has generic instance so all types used in generic are presented in this set.
+ ///
+ public ISet GenericTypes { get; set; }
+
public Field()
{
FieldType = null;
diff --git a/src/AddIns/Analysis/CodeQuality/Src/MainWindow.xaml b/src/AddIns/Analysis/CodeQuality/Src/MainWindow.xaml
index 7c4766722d..93f176f8c6 100644
--- a/src/AddIns/Analysis/CodeQuality/Src/MainWindow.xaml
+++ b/src/AddIns/Analysis/CodeQuality/Src/MainWindow.xaml
@@ -35,7 +35,7 @@
-
+
+ /// Parameters which are used by method
+ ///
+ public ISet Parameters { get; set; }
+
///
/// Types which are used in body of method
///
@@ -88,14 +93,29 @@ namespace ICSharpCode.CodeQualityAnalysis
///
public bool IsVirtual { get; set; }
+ ///
+ /// If the return type is generic instance so all types used in generic are presented in this set.
+ ///
+ public ISet GenericReturnTypes { get; set; }
+
+ ///
+ /// Whether the return type is generic instance
+ ///
+ public bool IsReturnTypeGenericInstance { get; set; }
+
public Method()
{
+ Parameters = new HashSet();
+
TypeUses = new HashSet();
MethodUses = new HashSet();
FieldUses = new HashSet();
+ GenericReturnTypes = new HashSet();
ReturnType = null;
Owner = null;
+
+ IsReturnTypeGenericInstance = false;
}
public BidirectionalGraph> BuildDependencyGraph()
@@ -108,4 +128,43 @@ namespace ICSharpCode.CodeQualityAnalysis
return Name;
}
}
+
+ public class MethodParameter
+ {
+ ///
+ /// The type of the parameter
+ ///
+ public Type ParameterType { get; set; }
+
+ ///
+ /// Whether the parameter is generic instance
+ ///
+ public bool IsGenericInstance { get; set; }
+
+ ///
+ /// Whether the parameter is in
+ ///
+ public bool IsIn { get; set; }
+
+ ///
+ /// Whether the parameter is out
+ ///
+ public bool IsOut { get; set; }
+
+ ///
+ /// Whether the parameter is optional
+ ///
+ public bool IsOptional { get; set; }
+
+ ///
+ /// If the parameter is generic instance so all types used in generic are presented in this set.
+ ///
+ public ISet GenericTypes { get; set; }
+
+ public MethodParameter()
+ {
+ GenericTypes = new HashSet();
+ IsGenericInstance = false;
+ }
+ }
}
diff --git a/src/AddIns/Analysis/CodeQuality/Src/MetricsReader.cs b/src/AddIns/Analysis/CodeQuality/Src/MetricsReader.cs
index 8fec682623..1077e23b7a 100644
--- a/src/AddIns/Analysis/CodeQuality/Src/MetricsReader.cs
+++ b/src/AddIns/Analysis/CodeQuality/Src/MetricsReader.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
@@ -175,6 +176,13 @@ namespace ICSharpCode.CodeQualityAnalysis
select t).SingleOrDefault();
type.BaseType = baseType; // if baseType is null so propably inherits from another assembly
+
+ if (typeDefinition.BaseType.IsGenericInstance)
+ {
+ type.IsBaseTypeGenericInstance = true;
+ type.GenericBaseTypes = ReadGenericArguments(type.Namespace.Module,
+ (GenericInstanceType)typeDefinition.BaseType);
+ }
}
// looks for implemented interfaces
@@ -189,6 +197,12 @@ namespace ICSharpCode.CodeQualityAnalysis
if (implementedIc != null)
type.ImplementedInterfaces.Add(implementedIc);
+
+ if (ic.IsGenericInstance)
+ {
+ type.GenericBaseTypes.UnionWith(ReadGenericArguments(type.Namespace.Module,
+ (GenericInstanceType)typeDefinition.BaseType));
+ }
}
}
@@ -227,11 +241,13 @@ namespace ICSharpCode.CodeQualityAnalysis
var declaringType =
(from n in type.Namespace.Module.Namespaces
from t in n.Types
- where t.Name == e.Name
+ where t.Name == FormatTypeName(eventDefinition.EventType)
select t).SingleOrDefault();
e.EventType = declaringType;
+ // TODO:check eventDefinition.OtherMethods
+
// Mono.Cecil threats Events as regular fields
// so I have to find a field and set IsEvent to true
@@ -270,13 +286,20 @@ namespace ICSharpCode.CodeQualityAnalysis
type.Fields.Add(field);
- var declaringType =
+ var fieldType =
(from n in type.Namespace.Module.Namespaces
from t in n.Types
- where t.Name == FormatTypeName(fieldDefinition.DeclaringType)
+ where t.Name == FormatTypeName(fieldDefinition.FieldType)
select t).SingleOrDefault();
- field.FieldType = declaringType;
+ if (fieldDefinition.FieldType.IsGenericInstance)
+ {
+ field.IsGenericInstance = true;
+ field.GenericTypes = ReadGenericArguments(type.Namespace.Module,
+ (GenericInstanceType)fieldDefinition.FieldType);
+ }
+
+ field.FieldType = fieldType;
}
}
@@ -313,6 +336,44 @@ namespace ICSharpCode.CodeQualityAnalysis
method.ReturnType = returnType; // if null so return type is outside of assembly
+ if (methodDefinition.ReturnType.IsGenericInstance)
+ {
+ method.IsReturnTypeGenericInstance = true;
+ method.GenericReturnTypes = ReadGenericArguments(type.Namespace.Module,
+ (GenericInstanceType) methodDefinition.ReturnType);
+ }
+
+ // reading types from parameters
+ foreach (var parameter in methodDefinition.Parameters)
+ {
+ var parameterType =
+ (from n in type.Namespace.Module.Namespaces
+ from t in n.Types
+ where t.Name == FormatTypeName(parameter.ParameterType)
+ select t).SingleOrDefault();
+
+ if (parameterType != null)
+ {
+ var param = new MethodParameter
+ {
+ ParameterType = parameterType,
+ IsIn = parameter.IsIn,
+ IsOut = parameter.IsOut,
+ IsOptional = parameter.IsOptional,
+ };
+
+ // generic parameters
+ if (parameter.ParameterType.IsGenericInstance)
+ {
+ param.IsGenericInstance = true;
+ param.GenericTypes = ReadGenericArguments(type.Namespace.Module,
+ (GenericInstanceType) parameter.ParameterType);
+ }
+
+ method.Parameters.Add(param);
+ }
+ }
+
type.Methods.Add(method);
}
@@ -357,7 +418,7 @@ namespace ICSharpCode.CodeQualityAnalysis
where m.Name == FormatMethodName(md)
select m).SingleOrDefault();
- if (findTargetMethod != null && type == method.ReturnType)
+ if (findTargetMethod != null && type == method.Owner)
method.MethodUses.Add(findTargetMethod);
}
@@ -374,6 +435,34 @@ namespace ICSharpCode.CodeQualityAnalysis
}
}
+ ///
+ /// Reads generic arguments from type and returns them as a set of types
+ ///
+ /// The module where are types located
+ /// The instance type
+ /// A set of types used by generic instance
+ public ISet ReadGenericArguments(Module module, GenericInstanceType genericInstance)
+ {
+ var types = new HashSet();
+
+ foreach (var parameter in genericInstance.GenericArguments)
+ {
+ var type =
+ (from n in module.Namespaces
+ from t in n.Types
+ where t.Name == FormatTypeName(parameter)
+ select t).SingleOrDefault();
+
+ if (type != null) //
+ types.Add(type);
+
+ if (parameter.IsGenericInstance)
+ types.UnionWith(ReadGenericArguments(module, (GenericInstanceType) parameter));
+ }
+
+ return types;
+ }
+
///
/// Reads instruction operand by recursive calling until non-instruction
/// operand is found
@@ -427,6 +516,8 @@ namespace ICSharpCode.CodeQualityAnalysis
/// A type name
public string FormatTypeName(TypeReference type)
{
+ type = type.GetElementType();
+
if (type.IsNested && type.DeclaringType != null)
{
return FormatTypeName(type.DeclaringType) + "+" + type.Name;
@@ -439,7 +530,7 @@ namespace ICSharpCode.CodeQualityAnalysis
bool hasNext = enumerator.MoveNext();
while (hasNext)
{
- builder.Append((enumerator.Current).Name);
+ builder.Append(enumerator.Current.Name);
hasNext = enumerator.MoveNext();
if (hasNext)
builder.Append(",");
diff --git a/src/AddIns/Analysis/CodeQuality/Src/Type.cs b/src/AddIns/Analysis/CodeQuality/Src/Type.cs
index 55c11abbad..1eb12fd1ae 100644
--- a/src/AddIns/Analysis/CodeQuality/Src/Type.cs
+++ b/src/AddIns/Analysis/CodeQuality/Src/Type.cs
@@ -124,6 +124,20 @@ namespace ICSharpCode.CodeQualityAnalysis
///
public bool IsNestedProtected { get; set; }
+ ///
+ /// Whether the base type is generic instance
+ ///
+ public bool IsBaseTypeGenericInstance { get; set; }
+
+ ///
+ /// If the base type is generic instance so all types used in generic are presented in this set.
+ ///
+ public ISet GenericBaseTypes { get; set; }
+
+ ///
+ /// If one of implemented interfaces is generic instance so all types used in generic are presented in this set.
+ ///
+ public ISet GenericImplementedInterfacesTypes { get; set; }
public Type()
{
@@ -132,9 +146,13 @@ namespace ICSharpCode.CodeQualityAnalysis
Events = new HashSet();
NestedTypes = new HashSet();
ImplementedInterfaces = new HashSet();
+ GenericBaseTypes = new HashSet();
+ GenericImplementedInterfacesTypes = new HashSet();
Owner = null;
BaseType = null;
+
+ IsBaseTypeGenericInstance = false;
}
///
@@ -148,14 +166,41 @@ namespace ICSharpCode.CodeQualityAnalysis
foreach (var method in Methods)
{
set.UnionWith(method.TypeUses);
+
+ foreach (var parameter in method.Parameters)
+ {
+ if (parameter.IsGenericInstance)
+ set.UnionWith(parameter.GenericTypes);
+
+ if (parameter.ParameterType != null)
+ set.Add(parameter.ParameterType);
+ }
+
+ if (method.IsReturnTypeGenericInstance)
+ set.UnionWith(method.GenericReturnTypes);
+
+ if (method.ReturnType != null)
+ set.Add(method.ReturnType);
}
foreach (var field in Fields)
{
+ if (field.IsGenericInstance)
+ set.UnionWith(field.GenericTypes);
+
if (field.FieldType != null) // if it is null so it is type from outside of this assembly
set.Add(field.FieldType); // TODO: find solution to handle them
}
+ if (BaseType != null)
+ set.Add(BaseType);
+
+ if (IsBaseTypeGenericInstance)
+ set.UnionWith(GenericBaseTypes);
+
+ set.UnionWith(ImplementedInterfaces);
+ set.UnionWith(GenericImplementedInterfacesTypes);
+
return set;
}