Browse Source

reimplement relationship concept from scratch

pull/18/head
Siegfried Pammer 14 years ago
parent
commit
816b65b729
  1. 5
      src/AddIns/Analysis/CodeQuality/CodeQuality.csproj
  2. 112
      src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs
  3. 38
      src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs
  4. 31
      src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs
  5. 22
      src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs
  6. 22
      src/AddIns/Analysis/CodeQuality/Engine/Dom/INode.cs
  7. 14
      src/AddIns/Analysis/CodeQuality/Engine/Dom/IValue.cs
  8. 33
      src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs
  9. 43
      src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs
  10. 64
      src/AddIns/Analysis/CodeQuality/Engine/Dom/NodeBase.cs
  11. 29
      src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs
  12. 91
      src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs
  13. 36
      src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs
  14. 47
      src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs
  15. 24
      src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs
  16. 2
      src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrixControl.cs
  17. 18
      src/AddIns/Analysis/CodeQuality/Gui/Controls/Matrix.cs
  18. 22
      src/AddIns/Analysis/CodeQuality/Gui/Controls/MatrixControl.cs
  19. 12
      src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs
  20. 1
      src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml
  21. 5
      src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml.cs
  22. 6
      src/AddIns/Analysis/CodeQuality/Gui/MatrixTreeNode.cs
  23. 2
      src/AddIns/Analysis/CodeQuality/Gui/NodeDescription.xaml
  24. 11
      src/AddIns/Analysis/CodeQuality/Gui/NodeDescription.xaml.cs
  25. 22
      src/AddIns/Analysis/CodeQuality/Gui/NodeDescriptionViewModel.cs
  26. 2
      src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs
  27. 56
      src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs
  28. 140
      src/AddIns/Analysis/CodeQuality/Utils/DoubleKeyDictionary.cs
  29. 6
      src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs
  30. 1
      src/AddIns/Analysis/CodeQuality/Utils/IColorizer.cs

5
src/AddIns/Analysis/CodeQuality/CodeQuality.csproj

@ -57,12 +57,10 @@ @@ -57,12 +57,10 @@
<Compile Include="Engine\Dom\AssemblyNode.cs" />
<Compile Include="Engine\Dom\EventNode.cs" />
<Compile Include="Engine\Dom\FieldNode.cs" />
<Compile Include="Engine\Dom\INode.cs" />
<Compile Include="Engine\Dom\IValue.cs" />
<Compile Include="Engine\Dom\NodeBase.cs" />
<Compile Include="Engine\Dom\MethodNode.cs" />
<Compile Include="Engine\Dom\NamespaceNode.cs" />
<Compile Include="Engine\Dom\PropertyNode.cs" />
<Compile Include="Engine\Dom\Relationship.cs" />
<Compile Include="Engine\Dom\TypeNode.cs" />
<Compile Include="Engine\ILAnalyzer.cs" />
<Compile Include="Engine\AssemblyAnalyzer.cs" />
@ -90,7 +88,6 @@ @@ -90,7 +88,6 @@
<Compile Include="Gui\NodeIconService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\DependencyColorizer.cs" />
<Compile Include="Utils\DoubleKeyDictionary.cs" />
<Compile Include="Utils\Extensions.cs" />
<Compile Include="Utils\IColorizer.cs" />
<Compile Include="Utils\Utils.cs" />

112
src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs

@ -49,41 +49,108 @@ namespace ICSharpCode.CodeQuality.Engine @@ -49,41 +49,108 @@ namespace ICSharpCode.CodeQuality.Engine
methodMappings = new Dictionary<IMethod, MethodNode>();
cecilMappings = new Dictionary<MemberReference, IEntity>();
// first we have to read all types so every method, field or property has a container
foreach (var type in compilation.GetAllTypeDefinitions()) {
ReadType(type);
}
foreach (TypeNode type in typeMappings.Values) {
foreach (var field in type.TypeDefinition.Fields) {
var tn = ReadType(type);
foreach (var field in type.Fields) {
var node = new FieldNode(field);
fieldMappings.Add(field, node);
try {
var cecilObj = loader.GetCecilObject((IUnresolvedField)field.UnresolvedMember);
var cecilObj = loader.GetCecilObject((IUnresolvedField)field.UnresolvedMember);
if (cecilObj != null)
cecilMappings[cecilObj] = field;
} catch (InvalidOperationException) {}
type.Children.Add(node);
tn.AddChild(node);
}
foreach (var method in type.TypeDefinition.Methods) {
foreach (var method in type.Methods) {
var node = new MethodNode(method);
methodMappings.Add(method, node);
try {
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)method.UnresolvedMember);
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)method.UnresolvedMember);
if (cecilObj != null)
cecilMappings[cecilObj] = method;
} catch (InvalidOperationException) {}
type.Children.Add(node);
tn.AddChild(node);
}
}
ILAnalyzer analyzer = new ILAnalyzer(loadedAssemblies.Select(asm => loader.GetCecilObject(asm)).ToArray(), this);
int count = methodMappings.Count + fieldMappings.Count;
int i = 0;
foreach (var element in methodMappings) {
int cc;
try {
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)element.Key.UnresolvedMember);
analyzer.Analyze(cecilObj.Body, element.Value, out cc);
} catch (InvalidOperationException) {}
Console.WriteLine("{0} of {1}", ++i, count);
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)element.Key.UnresolvedMember);
if (cecilObj != null)
analyzer.Analyze(cecilObj.Body, element.Value);
var node = element.Value;
var method = element.Key;
AddRelationshipsForType(node, method.ReturnType);
AddRelationshipsForAttributes(method.Attributes, node);
AddRelationshipsForAttributes(method.ReturnTypeAttributes, node);
AddRelationshipsForTypeParameters(method.TypeParameters, node);
foreach (var param in method.Parameters) {
AddRelationshipsForType(node, param.Type);
AddRelationshipsForAttributes(param.Attributes, node);
}
}
foreach (var element in fieldMappings) {
Console.WriteLine("{0} of {1}", ++i, count);
var node = element.Value;
var field = element.Key;
AddRelationshipsForType(node, field.Type);
AddRelationshipsForAttributes(field.Attributes, node);
}
return new ReadOnlyCollection<AssemblyNode>(assemblyMappings.Values.ToList());
}
void AddRelationshipsForTypeParameters(IList<ITypeParameter> typeParameters, NodeBase node)
{
foreach (var param in typeParameters) {
AddRelationshipsForAttributes(param.Attributes, node);
AddRelationshipsForType(node, param.EffectiveBaseClass);
}
}
void AddRelationshipsForTypes(IEnumerable<IType> directBaseTypes, NodeBase node)
{
foreach (var baseType in directBaseTypes) {
AddRelationshipsForType(node, baseType);
}
}
void AddRelationshipsForAttributes(IList<IAttribute> attributes, NodeBase node)
{
foreach (var attr in attributes) {
node.AddRelationship(methodMappings[attr.Constructor]);
}
}
void AddRelationshipsForType(NodeBase node, IType type)
{
type.AcceptVisitor(new AnalysisTypeVisitor(this, node));
}
class AnalysisTypeVisitor : TypeVisitor
{
NodeBase node;
AssemblyAnalyzer context;
public AnalysisTypeVisitor(AssemblyAnalyzer context, NodeBase node)
{
this.context = context;
this.node = node;
}
public override IType VisitTypeDefinition(ITypeDefinition type)
{
TypeNode typeNode;
if (context.typeMappings.TryGetValue(type, out typeNode))
node.AddRelationship(typeNode);
return base.VisitTypeDefinition(type);
}
}
IEnumerable<IUnresolvedAssembly> LoadAssemblies()
{
var resolver = new AssemblyResolver();
@ -101,7 +168,7 @@ namespace ICSharpCode.CodeQuality.Engine @@ -101,7 +168,7 @@ namespace ICSharpCode.CodeQuality.Engine
var asmDef = loader.GetCecilObject(assembly.AssemblyInfo.UnresolvedAssembly);
if (!namespaceMappings.TryGetValue(namespaceName + "," + asmDef.FullName, out result)) {
result = new NamespaceNode(namespaceName);
assembly.Children.Add(result);
assembly.AddChild(result);
namespaceMappings.Add(namespaceName + "," + asmDef.FullName, result);
}
return result;
@ -117,7 +184,7 @@ namespace ICSharpCode.CodeQuality.Engine @@ -117,7 +184,7 @@ namespace ICSharpCode.CodeQuality.Engine
return result;
}
void ReadType(ITypeDefinition type)
TypeNode ReadType(ITypeDefinition type)
{
var asm = GetOrCreateAssembly(type.ParentAssembly);
var ns = GetOrCreateNamespace(asm, type.Namespace);
@ -125,13 +192,14 @@ namespace ICSharpCode.CodeQuality.Engine @@ -125,13 +192,14 @@ namespace ICSharpCode.CodeQuality.Engine
var node = new TypeNode(type);
if (type.DeclaringTypeDefinition != null) {
if (typeMappings.TryGetValue(type.DeclaringTypeDefinition, out parent))
parent.Children.Add(node);
parent.AddChild(node);
else
throw new Exception("TypeNode not found: " + type.DeclaringTypeDefinition.FullName);
} else
ns.Children.Add(node);
ns.AddChild(node);
cecilMappings[loader.GetCecilObject(type.Parts.First())] = type;
typeMappings.Add(type, node);
return node;
}
class AssemblyResolver : DefaultAssemblyResolver

38
src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs

@ -3,56 +3,32 @@ @@ -3,56 +3,32 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class AssemblyNode : INode
public class AssemblyNode : NodeBase
{
public AssemblyNode(IAssembly assembly)
{
this.AssemblyInfo = assembly;
namespaces = new List<INode>();
namespaces = new List<NodeBase>();
}
public IAssembly AssemblyInfo { get; private set; }
public string Name {
public override string Name {
get { return AssemblyInfo.AssemblyName; }
}
List<INode> namespaces;
internal List<NodeBase> namespaces;
public IList<INode> Children {
public override IList<NodeBase> Children {
get { return namespaces; }
}
public IEnumerable<INode> Descendants {
get { return TreeTraversal.PreOrder(Children, node => node.Children); }
}
public IEnumerable<INode> Uses {
get { return Descendants.SelectMany(node => node.Uses); }
}
public IEnumerable<INode> UsedBy {
get { return Descendants.SelectMany(node => node.UsedBy); }
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
if (Uses.Contains(value))
r.AddRelationship(RelationshipType.Uses);
if (UsedBy.Contains(value))
r.AddRelationship(RelationshipType.UsedBy);
if (Descendants.Contains(value))
r.AddRelationship(RelationshipType.Contains);
return r;
}
}
}

31
src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs

@ -3,46 +3,23 @@ @@ -3,46 +3,23 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class EventNode : INode
public class EventNode : NodeBase
{
public string Name {
public override string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
public override IList<NodeBase> Children {
get { return null; }
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
if (Uses.Contains(value))
r.AddRelationship(RelationshipType.Uses);
if (UsedBy.Contains(value))
r.AddRelationship(RelationshipType.UsedBy);
return r;
}
}
}

22
src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs

@ -8,7 +8,7 @@ using ICSharpCode.NRefactory.TypeSystem; @@ -8,7 +8,7 @@ using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class FieldNode : INode
public class FieldNode : NodeBase
{
public IField FieldDefinition { get; private set; }
@ -17,28 +17,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom @@ -17,28 +17,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
this.FieldDefinition = fieldDefinition;
}
public string Name {
public override string Name {
get { return FieldDefinition.PrintFullName(); }
}
public IList<INode> Children {
public override IList<NodeBase> Children {
get { return null; }
}
public IEnumerable<INode> Uses {
get { return Enumerable.Empty<INode>(); }
}
public IEnumerable<INode> UsedBy {
get { return Enumerable.Empty<INode>(); }
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

22
src/AddIns/Analysis/CodeQuality/Engine/Dom/INode.cs

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
/// <summary>
/// Description of INode.
/// </summary>
public interface INode
{
string Name { get; }
IList<INode> Children { get; }
IEnumerable<INode> Uses { get; }
IEnumerable<INode> UsedBy { get; }
Relationship GetRelationship(INode value);
}
}

14
src/AddIns/Analysis/CodeQuality/Engine/Dom/IValue.cs

@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public interface IValue
{
string Text { get; }
}
}

33
src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs

@ -3,51 +3,30 @@ @@ -3,51 +3,30 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class MethodNode : INode
public class MethodNode : NodeBase
{
public IMethod MethodDefinition { get; private set; }
public int CyclomaticComplexity { get; set; }
public MethodNode(IMethod methodDefinition)
{
this.MethodDefinition = methodDefinition;
uses = new List<INode>();
usedBy = new List<INode>();
}
public string Name {
public override string Name {
get { return MethodDefinition.PrintFullName(); }
}
public IList<INode> Children {
public override IList<NodeBase> Children {
get { return null; }
}
internal IList<INode> uses, usedBy;
public IEnumerable<INode> Uses {
get { return uses; }
}
public IEnumerable<INode> UsedBy {
get { return usedBy; }
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
if (Uses.Contains(value))
r.AddRelationship(RelationshipType.Uses);
if (UsedBy.Contains(value))
r.AddRelationship(RelationshipType.UsedBy);
return r;
}
}
}

43
src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
@ -10,46 +11,24 @@ using ICSharpCode.NRefactory.Utils; @@ -10,46 +11,24 @@ using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class NamespaceNode : INode
public class NamespaceNode : NodeBase
{
public NamespaceNode(string name)
{
this.Name = name;
types = new List<INode>();
this.name = name;
types = new List<NodeBase>();
}
public string Name { get; private set; }
string name;
List<INode> types;
public IList<INode> Children {
get { return types; }
}
public IEnumerable<INode> Descendants {
get { return TreeTraversal.PreOrder(Children, node => node.Children); }
}
public IEnumerable<INode> Uses {
get { return Descendants.SelectMany(node => node.Uses); }
public override string Name {
get { return name; }
}
public IEnumerable<INode> UsedBy {
get { return Descendants.SelectMany(node => node.UsedBy); }
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
if (Uses.Contains(value))
r.AddRelationship(RelationshipType.Uses);
if (UsedBy.Contains(value))
r.AddRelationship(RelationshipType.UsedBy);
if (Descendants.Contains(value))
r.AddRelationship(RelationshipType.Contains);
return r;
List<NodeBase> types;
public override IList<NodeBase> Children {
get { return types; }
}
}
}

64
src/AddIns/Analysis/CodeQuality/Engine/Dom/NodeBase.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public abstract class NodeBase
{
public abstract string Name { get; }
public abstract IList<NodeBase> Children { get; }
public NodeBase Parent { get; private set; }
internal IEnumerable<NodeBase> AncestorsAndSelf {
get {
var node = this;
while (node != null) {
yield return node;
node = node.Parent;
}
}
}
public void AddRelationship(NodeBase reference)
{
foreach (NodeBase pa in AncestorsAndSelf) {
if (reference.AncestorsAndSelf.Contains(pa)) break;
foreach (NodeBase pb in reference.AncestorsAndSelf) {
if (AncestorsAndSelf.Contains(pb)) break;
pa.AddRelationshipInternal(pb);
}
}
}
protected Dictionary<NodeBase, int> relationships = new Dictionary<NodeBase, int>();
void AddRelationshipInternal(NodeBase reference)
{
if (!relationships.ContainsKey(reference))
relationships[reference] = 0;
relationships[reference]++;
}
public void AddChild(NodeBase child)
{
child.Parent = this;
Children.Add(child);
}
public int GetUses(NodeBase value)
{
if (this == value)
return -1;
int uses;
if (relationships.TryGetValue(value, out uses))
return uses;
return 0;
}
}
}

29
src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs

@ -3,40 +3,23 @@ @@ -3,40 +3,23 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class PropertyNode : INode
public class PropertyNode : NodeBase
{
public string Name {
public override string Name {
get {
throw new NotImplementedException();
}
}
public IList<INode> Children {
public override IList<NodeBase> Children {
get { return null; }
}
public IEnumerable<INode> Uses {
get {
throw new NotImplementedException();
}
}
public IEnumerable<INode> UsedBy {
get {
throw new NotImplementedException();
}
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
return r;
}
}
}

91
src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs

@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
/// <summary>
/// Description of Relationship.
/// </summary>
public class Relationship : IValue
{
public ISet<RelationshipType> Relationships { get; private set; }
public int OccurrenceCount { get; private set; }
public string Text { get { return OccurrenceCount.ToString(); } }
public INode To { get; set; }
public INode From { get; set; }
public Relationship()
{
Relationships = new HashSet<RelationshipType>();
}
public void AddRelationship(RelationshipType type)
{
if (type == RelationshipType.Uses || type == RelationshipType.UsedBy)
OccurrenceCount++;
Relationships.Add(type);
}
public string InfoText {
get {
string text = "is not related to";
if (Relationships.Any(r => r == RelationshipType.Uses))
text = "uses";
else if (Relationships.Any(r => r == RelationshipType.UsedBy))
text = "is used by";
else if (Relationships.Any(r => r == RelationshipType.Same))
text = "is the same as";
return string.Format("{0} {1} {2}", From.Name, text, To.Name);
}
}
public override string ToString()
{
var builder = new StringBuilder();
foreach (var relationship in Relationships)
builder.Append(relationship + " ");
builder.Append(OccurrenceCount);
return builder.ToString();
}
}
/// <summary>
/// Type of relationship between two INodes.
/// </summary>
public enum RelationshipType
{
/// <summary>
/// a and b are not related to each other.
/// </summary>
None,
/// <summary>
/// a contains b.
/// </summary>
Contains,
/// <summary>
/// a uses b.
/// </summary>
Uses,
/// <summary>
/// a is used by b.
/// </summary>
UsedBy,
/// <summary>
/// a and b are the same INode
/// </summary>
Same
}
}

36
src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs

@ -10,50 +10,24 @@ using ICSharpCode.NRefactory.Utils; @@ -10,50 +10,24 @@ using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.CodeQuality.Engine.Dom
{
public class TypeNode : INode
public class TypeNode : NodeBase
{
public ITypeDefinition TypeDefinition { get; private set; }
public TypeNode(ITypeDefinition typeDefinition)
{
this.TypeDefinition = typeDefinition;
children = new List<INode>();
children = new List<NodeBase>();
}
public string Name {
public override string Name {
get { return TypeDefinition.Name; }
}
List<INode> children;
List<NodeBase> children;
public IList<INode> Children {
public override IList<NodeBase> Children {
get { return children; }
}
public IEnumerable<INode> Descendants {
get { return TreeTraversal.PreOrder(Children, node => node.Children); }
}
public IEnumerable<INode> Uses {
get { return Descendants.SelectMany(node => node.Uses); }
}
public IEnumerable<INode> UsedBy {
get { return Descendants.SelectMany(node => node.UsedBy); }
}
public Relationship GetRelationship(INode value)
{
Relationship r = new Relationship();
if (value == this)
r.AddRelationship(RelationshipType.Same);
if (Uses.Contains(value))
r.AddRelationship(RelationshipType.Uses);
if (UsedBy.Contains(value))
r.AddRelationship(RelationshipType.UsedBy);
if (Descendants.Contains(value))
r.AddRelationship(RelationshipType.Contains);
return r;
}
}
}

47
src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs

@ -27,9 +27,9 @@ namespace ICSharpCode.CodeQuality.Engine @@ -27,9 +27,9 @@ namespace ICSharpCode.CodeQuality.Engine
this.mappings = mappings;
}
public void Analyze(MethodBody body, MethodNode analyzedMethod, out int cyclomaticComplexity)
public void Analyze(MethodBody body, MethodNode analyzedMethod)
{
cyclomaticComplexity = 0;
analyzedMethod.CyclomaticComplexity = 0;
if (body == null)
return;
@ -37,42 +37,23 @@ namespace ICSharpCode.CodeQuality.Engine @@ -37,42 +37,23 @@ namespace ICSharpCode.CodeQuality.Engine
foreach (var instruction in body.Instructions) {
// IL cyclomatic complexity
if (instruction.OpCode.FlowControl == FlowControl.Cond_Branch)
cyclomaticComplexity++;
analyzedMethod.CyclomaticComplexity++;
var operand = ReadOperand(instruction);
if (operand is MethodDefinition) {
var md = (MethodDefinition)operand;
if (assemblies.Contains(md.DeclaringType.Module.Assembly) && mappings.cecilMappings.ContainsKey(md)) {
var opMethod = (IMethod)mappings.cecilMappings[md];
var methodNode = mappings.methodMappings[opMethod];
analyzedMethod.uses.Add(methodNode);
methodNode.usedBy.Add(analyzedMethod);
if (operand is MethodReference) {
var md = ((MethodReference)operand).Resolve();
if (md != null && assemblies.Contains(md.DeclaringType.Module.Assembly) && mappings.cecilMappings.ContainsKey(md)) {
var methodNode = mappings.methodMappings[(IMethod)mappings.cecilMappings[md.Resolve()]];
analyzedMethod.AddRelationship(methodNode);
}
} else if (operand is FieldReference) {
var fd = ((FieldReference)operand).Resolve();
if (fd != null && assemblies.Contains(fd.DeclaringType.Module.Assembly) && mappings.cecilMappings.ContainsKey(fd)) {
var fieldNode = mappings.fieldMappings[(IField)mappings.cecilMappings[fd]];
analyzedMethod.AddRelationship(fieldNode);
}
}
//
// if (operand is MethodDefinition && ((MethodDefinition)operand).DeclaringType.Module.Assembly == assemblyDefinition) {
// var md = (MethodDefinition)operand;
// if (md.DeclaringType.Name == "" || md.DeclaringType.Name.StartsWith("<")) {
// // TODO : Handle generated members
// } else {
// var opMethod = (IMethod)cecilMappings[md];
// var methodNode = methodMappings[opMethod];
// m.typeUses.Add(methodNode.DeclaringType);
// m.methodUses.Add(methodNode);
// }
// }
//
// if (operand is FieldDefinition && ((FieldDefinition)operand).DeclaringType.Module.Assembly == assemblyDefinition) {
// var fd = (FieldDefinition)operand;
// if (fd.DeclaringType.Name == "" || fd.DeclaringType.Name.StartsWith("<")) {
// // TODO : Handle generated members
// } else {
// var field = (IField)cecilMappings[fd];
// var fieldNode = fieldMappings[field];
// m.fieldUses.Add(fieldNode);
// }
// }
}
}

24
src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs

@ -10,23 +10,13 @@ using ICSharpCode.CodeQuality.Engine.Dom; @@ -10,23 +10,13 @@ using ICSharpCode.CodeQuality.Engine.Dom;
namespace ICSharpCode.CodeQuality.Gui
{
public class DependencyMatrix : VisibleMatrix<INode, Relationship>
{
protected override Relationship GetCellValue(int rowIndex, int columnIndex)
public class DependencyMatrix : VisibleMatrix<NodeBase, Tuple<int, int>>
{
protected override Tuple<int, int> GetCellValue(int rowIndex, int columnIndex)
{
var toRelationship = HeaderRows[rowIndex].Value.GetRelationship(HeaderColumns[columnIndex].Value);
var fromRelationship = HeaderColumns[columnIndex].Value.GetRelationship(HeaderRows[rowIndex].Value);
toRelationship.From = HeaderRows[rowIndex].Value;
toRelationship.To = HeaderColumns[columnIndex].Value;
// add other way
foreach (var relationship in fromRelationship.Relationships) {
if (relationship == RelationshipType.Uses)
toRelationship.AddRelationship(RelationshipType.UsedBy);
}
return toRelationship;
int a = HeaderRows[rowIndex].Value.GetUses(HeaderColumns[columnIndex].Value);
int b = HeaderColumns[columnIndex].Value.GetUses(HeaderRows[rowIndex].Value);
return Tuple.Create(a, b);
}
}
}
}

2
src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrixControl.cs

@ -6,7 +6,7 @@ using ICSharpCode.CodeQuality.Engine.Dom; @@ -6,7 +6,7 @@ using ICSharpCode.CodeQuality.Engine.Dom;
namespace ICSharpCode.CodeQuality.Gui
{
public class DependencyMatrixControl : MatrixControl<VisibleMatrix<INode, Relationship>, INode, Relationship>
public class DependencyMatrixControl : MatrixControl<VisibleMatrix<NodeBase, Tuple<int, int>>, NodeBase, Tuple<int, int>>
{
}

18
src/AddIns/Analysis/CodeQuality/Gui/Controls/Matrix.cs

@ -27,13 +27,10 @@ namespace ICSharpCode.CodeQuality.Gui @@ -27,13 +27,10 @@ namespace ICSharpCode.CodeQuality.Gui
}
}
private DoubleKeyDictionary<TItem, TItem, TValue> cache;
protected Matrix()
{
headerRows = new List<Cell<TItem>>();
headerColumns = new List<Cell<TItem>>();
cache = new DoubleKeyDictionary<TItem, TItem, TValue>();
}
public void AddRow(TItem value)
@ -46,16 +43,6 @@ namespace ICSharpCode.CodeQuality.Gui @@ -46,16 +43,6 @@ namespace ICSharpCode.CodeQuality.Gui
headerColumns.Add(new Cell<TItem>(value));
}
private TValue GetFromCache(TItem rowIndex, TItem columnIndex)
{
return cache[rowIndex, columnIndex];
}
private void SaveToCache(TItem rowIndex, TItem columnIndex, TValue result)
{
cache.Add(rowIndex, columnIndex, result);
}
public TValue this[int rowIndex, int columnIndex]
{
get
@ -67,12 +54,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -67,12 +54,7 @@ namespace ICSharpCode.CodeQuality.Gui
var from = HeaderRows[rowIndex].Value;
var to = HeaderColumns[columnIndex].Value;
var cacheResult = GetFromCache(from, to);
if (cacheResult != null)
return cacheResult;
var result = GetCellValue(rowIndex, columnIndex);
SaveToCache(from, to, result);
return result;
}
}

22
src/AddIns/Analysis/CodeQuality/Gui/Controls/MatrixControl.cs

@ -18,7 +18,6 @@ using PointF = System.Drawing.PointF; @@ -18,7 +18,6 @@ using PointF = System.Drawing.PointF;
namespace ICSharpCode.CodeQuality.Gui
{
public class MatrixControl<TMatrix, TItem, TValue> : FrameworkElement, IScrollInfo
where TValue : IValue
where TMatrix : Matrix<TItem, TValue>
{
public event EventHandler<HoveredCellEventArgs<TValue>> HoveredCellChanged;
@ -94,7 +93,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -94,7 +93,7 @@ namespace ICSharpCode.CodeQuality.Gui
InvalidateVisual();
}
public void HighlightLine(HeaderType type, INode node)
public void HighlightLine(HeaderType type, NodeBase node)
{
var items = type == HeaderType.Columns ? Matrix.HeaderColumns : Matrix.HeaderRows;
for (int i = 0; i < items.Count; i++) {
@ -137,13 +136,13 @@ namespace ICSharpCode.CodeQuality.Gui @@ -137,13 +136,13 @@ namespace ICSharpCode.CodeQuality.Gui
}
}
protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
{
base.OnMouseDown(e);
Relationship relationship = HoveredCell.Value as Relationship;
Console.WriteLine("To: " + relationship.To.Name);
Console.WriteLine("From:" + relationship.From.Name);
}
// protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
// {
// base.OnMouseDown(e);
// Tuple<int, int> relationship = HoveredCell.Value as Tuple<int, int>;
// Console.WriteLine("To: " + relationship.To.Name);
// Console.WriteLine("From:" + relationship.From.Name);
// }
protected void SetHoveredCell()
{
@ -259,9 +258,10 @@ namespace ICSharpCode.CodeQuality.Gui @@ -259,9 +258,10 @@ namespace ICSharpCode.CodeQuality.Gui
drawingContext.DrawRectangle(brush, null, rect);
}
if (!RenderZeroes && value != null && value.Text != "0") // rendering zeroes would be distracting
string text = Colorizer.GetText(value);
if (!RenderZeroes && value != null && text != "0") // rendering zeroes would be distracting
drawingContext.DrawImage(
CreateText(value.Text),
CreateText(text),
new Rect(i * CellWidth - offsetDiffX, j * CellHeight - offsetDiffY, CellWidth, CellHeight));
}
}

12
src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -45,7 +45,7 @@ namespace ICSharpCode.CodeQuality.Gui
}
public void Update(IEnumerable<INode> nodes)
public void Update(IEnumerable<NodeBase> nodes)
{
this.Visibility = Visibility.Visible;
@ -70,7 +70,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -70,7 +70,7 @@ namespace ICSharpCode.CodeQuality.Gui
}
void AddChildrenToMatrix(DependencyMatrix matrix, IEnumerable<INode> nodes)
void AddChildrenToMatrix(DependencyMatrix matrix, IEnumerable<NodeBase> nodes)
{
foreach (var node in nodes) {
matrix.AddColumn(node);
@ -105,7 +105,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -105,7 +105,7 @@ namespace ICSharpCode.CodeQuality.Gui
void SetVisibleItemsForRows()
{
List<INode> leftNodes = new List<INode>();
List<NodeBase> leftNodes = new List<NodeBase>();
foreach (MatrixTreeNode node in leftTree.Items.OfType<MatrixTreeNode>()) {
var n = node.Node;
leftNodes.Add(n);
@ -126,7 +126,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -126,7 +126,7 @@ namespace ICSharpCode.CodeQuality.Gui
void SetVisibleItemsForColumns()
{
List<INode> topNodes = new List<INode>();
List<NodeBase> topNodes = new List<NodeBase>();
foreach (MatrixTreeNode node in topTree.Items.OfType<MatrixTreeNode>()) {
var n = node.Node;
topNodes.Add(n);
@ -165,7 +165,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -165,7 +165,7 @@ namespace ICSharpCode.CodeQuality.Gui
return null;
}
void MatrixHoveredCellChanged(object sender, HoveredCellEventArgs<Relationship> e)
void MatrixHoveredCellChanged(object sender, HoveredCellEventArgs<Tuple<int, int>> e)
{
// need to add 1 to index, because first item in treeview is invisible root node
if (e.HoveredCell.RowIndex < leftTree.Items.Count) {
@ -174,7 +174,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -174,7 +174,7 @@ namespace ICSharpCode.CodeQuality.Gui
if (e.HoveredCell.ColumnIndex < topTree.Items.Count) {
topTree.SelectedItem = topTree.Items[e.HoveredCell.ColumnIndex + 1];
}
nodeDescriptionViewModel.Relationship = e.HoveredCell.Value;
// nodeDescriptionViewModel.Tuple<int, int> = e.HoveredCell.Value;
}
#endregion
}

1
src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
<DockPanel>
<ToolBar DockPanel.Dock="Top">
<Button Click="AddAssemblyClick">Add Assembly</Button>
<Button Click="RefreshClick">Refresh</Button>
</ToolBar>
<TabControl>
<TabItem Header="Dependency Matrix">

5
src/AddIns/Analysis/CodeQuality/Gui/MainView.xaml.cs

@ -43,5 +43,10 @@ namespace ICSharpCode.CodeQuality.Gui @@ -43,5 +43,10 @@ namespace ICSharpCode.CodeQuality.Gui
context.AddAssemblyFiles(fileDialog.FileNames);
matrix.Update(context.Analyze());
}
void RefreshClick(object sender, RoutedEventArgs e)
{
matrix.Update(context.Analyze());
}
}
}

6
src/AddIns/Analysis/CodeQuality/Gui/MatrixTreeNode.cs

@ -12,13 +12,13 @@ namespace ICSharpCode.CodeQuality.Gui @@ -12,13 +12,13 @@ namespace ICSharpCode.CodeQuality.Gui
/// </summary>
public class MatrixTreeNode : SharpTreeNode
{
INode node;
NodeBase node;
public INode Node {
public NodeBase Node {
get { return node; }
}
public MatrixTreeNode(INode node)
public MatrixTreeNode(NodeBase node)
{
this.node = node;
}

2
src/AddIns/Analysis/CodeQuality/Gui/NodeDescription.xaml

@ -27,7 +27,7 @@ @@ -27,7 +27,7 @@
<!--
<TextBlock Text="{Binding Uses}" Grid.Column="1" Grid.Row="3"></TextBlock>
<TextBlock Text="{Binding UsedBy}" Grid.Column="1" Grid.Row="4"></TextBlock>-->
<TextBlock Text="{Binding Relationship.InfoText}" Grid.Row="3" Grid.ColumnSpan="2" />
<TextBlock Text="{Binding InfoText}" Grid.Row="3" Grid.ColumnSpan="2" />
</Grid>
</Grid>
</Border>

11
src/AddIns/Analysis/CodeQuality/Gui/NodeDescription.xaml.cs

@ -1,11 +1,6 @@ @@ -1,11 +1,6 @@
/*
* Created by SharpDevelop.
* User: Peter Forstmeier
* Date: 26.01.2012
* Time: 20:20
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Text;

22
src/AddIns/Analysis/CodeQuality/Gui/NodeDescriptionViewModel.cs

@ -26,9 +26,9 @@ namespace ICSharpCode.CodeQuality.Gui @@ -26,9 +26,9 @@ namespace ICSharpCode.CodeQuality.Gui
{
public class NodeDescriptionViewModel : ViewModelBase
{
INode node;
NodeBase node;
public INode Node
public NodeBase Node
{
get { return node; }
set {
@ -39,26 +39,16 @@ namespace ICSharpCode.CodeQuality.Gui @@ -39,26 +39,16 @@ namespace ICSharpCode.CodeQuality.Gui
}
}
Relationship relationship;
public Relationship Relationship {
get { return relationship; }
set {
relationship = value;
base.RaisePropertyChanged(() => Relationship);
}
}
public int Uses {get {return Node.Uses.Count();}}
public int UsesBy {get {return Node.UsedBy.Count();}}
// public int Uses {get {return Node.Uses.Count();}}
//
// public int UsesBy {get {return Node.UsedBy.Count();}}
public string ClassType
{
get
{
var n = node.GetType().Name;
Console.WriteLine(n.Substring(0,n.Length -4));
// Console.WriteLine(n.Substring(0,n.Length -4));
return (n.Substring(0,n.Length -4));
}
}

2
src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs

@ -81,7 +81,7 @@ namespace ICSharpCode.CodeQuality.Gui @@ -81,7 +81,7 @@ namespace ICSharpCode.CodeQuality.Gui
return Field;
}
public static BitmapSource GetIcon(INode node)
public static BitmapSource GetIcon(NodeBase node)
{
if (node is AssemblyNode)
return GetIcon((AssemblyNode)node);

56
src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs

@ -13,7 +13,7 @@ namespace ICSharpCode.CodeQuality @@ -13,7 +13,7 @@ namespace ICSharpCode.CodeQuality
/// <summary>
/// Description of DependencyColorizer.
/// </summary>
public class DependencyColorizer : IColorizer<Relationship>
public class DependencyColorizer : IColorizer<Tuple<int, int>>
{
private Dictionary<Color, SolidColorBrush> cache;
@ -22,9 +22,9 @@ namespace ICSharpCode.CodeQuality @@ -22,9 +22,9 @@ namespace ICSharpCode.CodeQuality
cache = new Dictionary<Color, SolidColorBrush>();
}
public SolidColorBrush GetColorBrush(Relationship relationship)
public SolidColorBrush GetColorBrush(Tuple<int, int> value)
{
var color = GetColor(relationship);
var color = GetColor(value);
if (cache.ContainsKey(color))
return cache[color];
@ -36,24 +36,32 @@ namespace ICSharpCode.CodeQuality @@ -36,24 +36,32 @@ namespace ICSharpCode.CodeQuality
return brush;
}
public Color GetColor(Relationship relationship)
public Color GetColor(Tuple<int, int> value)
{
if (relationship == null)
// null or both = 0 => None
if (value == null)
return Colors.Transparent;
if (relationship.Relationships.Any(r => r == RelationshipType.Uses))
if (value.Item1 == 0 && value.Item2 == 0)
return Colors.Transparent;
// both = -1 => Same
if (value.Item1 == -1 && value.Item2 == -1)
return Colors.Gray;
// both > 0 => UsesAndUsedBy
if (value.Item1 > 0 && value.Item2 > 0)
return Colors.Turquoise;
// a > 0 => Uses
if (value.Item1 > 0)
return Colors.LightGreen;
if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy))
// b > 0 => UsedBy
if (value.Item2 > 0)
return Colors.LightBlue;
if (relationship.Relationships.Any(r => r == RelationshipType.Same))
return Colors.Gray;
return Colors.Transparent;
}
public SolidColorBrush GetColorBrushMixedWith(Color color, Relationship relationship)
public SolidColorBrush GetColorBrushMixedWith(Color color, Tuple<int, int> value)
{
var mixedColor = GetColor(relationship);
var mixedColor = GetColor(value);
mixedColor = mixedColor.MixedWith(color);
if (cache.ContainsKey(mixedColor))
@ -66,6 +74,28 @@ namespace ICSharpCode.CodeQuality @@ -66,6 +74,28 @@ namespace ICSharpCode.CodeQuality
return brush;
}
public string GetText(Tuple<int, int> value)
{
// null or both = 0 => None
if (value == null)
return "";
if (value.Item1 == 0 && value.Item2 == 0)
return "";
// both = -1 => Same
if (value.Item1 == -1 && value.Item2 == -1)
return "";
// both > 0 => UsesAndUsedBy
if (value.Item1 > 0 && value.Item2 > 0)
return value.Item1.ToString();
// a > 0 => Uses
if (value.Item1 > 0)
return value.Item1.ToString();
// b > 0 => UsedBy
if (value.Item2 > 0)
return value.Item2.ToString();
return "";
}
}
}

140
src/AddIns/Analysis/CodeQuality/Utils/DoubleKeyDictionary.cs

@ -1,140 +0,0 @@ @@ -1,140 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
namespace ICSharpCode.CodeQuality
{
public class DoubleKeyDictionary<K, T, V> :
IEnumerable<DoubleKeyPairValue<K, T, V>>,
IEquatable<DoubleKeyDictionary<K, T, V>>
{
private Dictionary<T, V> innerDictionary;
public DoubleKeyDictionary()
{
OuterDictionary = new Dictionary<K, Dictionary<T, V>>();
}
private Dictionary<K, Dictionary<T, V>> OuterDictionary { get; set; }
public void Add(K key1, T key2, V value)
{
if (OuterDictionary.ContainsKey(key1)) {
if (innerDictionary.ContainsKey(key2)) {
OuterDictionary[key1][key2] = value;
}
else {
innerDictionary = OuterDictionary[key1];
innerDictionary.Add(key2, value);
OuterDictionary[key1] = innerDictionary;
}
}
else {
innerDictionary = new Dictionary<T, V>();
innerDictionary[key2] = value;
OuterDictionary.Add(key1, innerDictionary);
}
}
public V this[K index1, T index2]
{
get
{
Dictionary<T, V> value1;
OuterDictionary.TryGetValue(index1, out value1);
if (value1 == null)
return default(V);
V value2;
value1.TryGetValue(index2, out value2);
if (value2 == null)
return default(V);
return value2;
}
set
{
Add(index1, index2, value);
}
}
#region IEnumerable<DoubleKeyPairValue<K,T,V>> Members
public IEnumerator<DoubleKeyPairValue<K, T, V>> GetEnumerator()
{
foreach (KeyValuePair<K, Dictionary<T, V>> outer in OuterDictionary)
foreach (KeyValuePair<T, V> inner in outer.Value)
yield return new DoubleKeyPairValue<K, T, V>(outer.Key, inner.Key, inner.Value);
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region IEquatable<DoubleKeyDictionary<K,T,V>> Members
public bool Equals(DoubleKeyDictionary<K, T, V> other)
{
if (OuterDictionary.Keys.Count != other.OuterDictionary.Keys.Count)
return false;
bool isEqual = true;
foreach (KeyValuePair<K, Dictionary<T, V>> innerItems in OuterDictionary) {
if (!other.OuterDictionary.ContainsKey(innerItems.Key))
isEqual = false;
if (!isEqual)
break;
// here we can be sure that the key is in both lists,
// but we need to check the contents of the inner dictionary
Dictionary<T, V> otherInnerDictionary = other.OuterDictionary[innerItems.Key];
foreach (KeyValuePair<T, V> innerValue in innerItems.Value) {
if (!otherInnerDictionary.ContainsValue(innerValue.Value))
isEqual = false;
if (!otherInnerDictionary.ContainsKey(innerValue.Key))
isEqual = false;
}
if (!isEqual)
break;
}
return isEqual;
}
#endregion
}
public class DoubleKeyPairValue<K, T, V>
{
public K Key1 { get; set; }
public T Key2 { get; set; }
public V Value { get; set; }
public DoubleKeyPairValue(K key1, T key2, V value) {
Key1 = key1;
Key2 = key2;
Value = value;
}
public override string ToString()
{
return Key1.ToString() + " - " + Key2.ToString() + " - " + Value.ToString();
}
}
}

6
src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs

@ -19,16 +19,16 @@ namespace ICSharpCode.CodeQuality @@ -19,16 +19,16 @@ namespace ICSharpCode.CodeQuality
/// </summary>
public static class Extensions
{
public static void FillTree(SharpTreeView tree, IEnumerable<INode> rootNodes)
public static void FillTree(SharpTreeView tree, IEnumerable<NodeBase> rootNodes)
{
tree.Root = new SharpTreeNode();
if (rootNodes != null)
CreateItems(rootNodes, tree.Root);
}
static void CreateItems(IEnumerable<INode> nodes, SharpTreeNode parent)
static void CreateItems(IEnumerable<NodeBase> nodes, SharpTreeNode parent)
{
foreach (INode node in nodes) {
foreach (NodeBase node in nodes) {
var item = new MatrixTreeNode(node);
parent.Children.Add(item);
if (node.Children != null)

1
src/AddIns/Analysis/CodeQuality/Utils/IColorizer.cs

@ -16,5 +16,6 @@ namespace ICSharpCode.CodeQuality @@ -16,5 +16,6 @@ namespace ICSharpCode.CodeQuality
SolidColorBrush GetColorBrush(TValue value);
SolidColorBrush GetColorBrushMixedWith(Color color, TValue value);
Color GetColor(TValue value);
string GetText(TValue value);
}
}

Loading…
Cancel
Save