Browse Source

implement method usage in method bodies

pull/18/head
Siegfried Pammer 14 years ago
parent
commit
13965a78f9
  1. 9
      SharpDevelop.sln
  2. 4
      src/AddIns/Analysis/CodeQuality/CodeQuality.csproj
  3. 87
      src/AddIns/Analysis/CodeQuality/Engine/AssemblyAnalyzer.cs
  4. 25
      src/AddIns/Analysis/CodeQuality/Engine/Dom/AssemblyNode.cs
  5. 10
      src/AddIns/Analysis/CodeQuality/Engine/Dom/EventNode.cs
  6. 24
      src/AddIns/Analysis/CodeQuality/Engine/Dom/FieldNode.cs
  7. 33
      src/AddIns/Analysis/CodeQuality/Engine/Dom/MethodNode.cs
  8. 19
      src/AddIns/Analysis/CodeQuality/Engine/Dom/NamespaceNode.cs
  9. 4
      src/AddIns/Analysis/CodeQuality/Engine/Dom/PropertyNode.cs
  10. 29
      src/AddIns/Analysis/CodeQuality/Engine/Dom/Relationship.cs
  11. 26
      src/AddIns/Analysis/CodeQuality/Engine/Dom/TypeNode.cs
  12. 72
      src/AddIns/Analysis/CodeQuality/Engine/ILAnalyzer.cs
  13. 2
      src/AddIns/Analysis/CodeQuality/Gui/Controls/DependencyMatrix.cs
  14. 2
      src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml
  15. 33
      src/AddIns/Analysis/CodeQuality/Gui/DependencyMatrixView.xaml.cs
  16. 2
      src/AddIns/Analysis/CodeQuality/Gui/NodeIconService.cs
  17. 6
      src/AddIns/Analysis/CodeQuality/Utils/DependencyColorizer.cs
  18. 12
      src/AddIns/Analysis/CodeQuality/Utils/Extensions.cs
  19. 20
      src/AddIns/Analysis/CodeQuality/Utils/Utils.cs

9
SharpDevelop.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.2.0.8363-alpha # SharpDevelop 4.2.0.8380-alpha
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
EndProjectSection EndProjectSection
@ -505,10 +505,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceAnalysis", "src\AddIn
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MachineSpecifications", "src\AddIns\Analysis\MachineSpecifications\MachineSpecifications\MachineSpecifications.csproj", "{D1DA3B8F-7313-4BDA-8880-461C5F007751}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MachineSpecifications", "src\AddIns\Analysis\MachineSpecifications\MachineSpecifications\MachineSpecifications.csproj", "{D1DA3B8F-7313-4BDA-8880-461C5F007751}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeQuality", "CodeQuality", "{558479FB-A397-4EE9-A1AD-879F80D1FCD0}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeQuality", "src\AddIns\Analysis\CodeQuality\CodeQuality.csproj", "{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeQuality", "src\AddIns\Analysis\CodeQuality\CodeQuality.csproj", "{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7}"
EndProject EndProject
Project("{00000000-0000-0000-0000-000000000000}") = "Tools", "src\Tools\Tools.build", "{3DF4060F-5EE0-41CF-8096-F27355FD5511}" Project("{00000000-0000-0000-0000-000000000000}") = "Tools", "src\Tools\Tools.build", "{3DF4060F-5EE0-41CF-8096-F27355FD5511}"
@ -1266,7 +1262,6 @@ Global
{08CE9972-283B-44F4-82FA-966F7DFA6B7A} = {F355E45F-F54F-4B42-8916-9A633A392789} {08CE9972-283B-44F4-82FA-966F7DFA6B7A} = {F355E45F-F54F-4B42-8916-9A633A392789}
{CE498514-D12D-4B6E-AE0E-FEC29BD43748} = {F355E45F-F54F-4B42-8916-9A633A392789} {CE498514-D12D-4B6E-AE0E-FEC29BD43748} = {F355E45F-F54F-4B42-8916-9A633A392789}
{D1DA3B8F-7313-4BDA-8880-461C5F007751} = {F355E45F-F54F-4B42-8916-9A633A392789} {D1DA3B8F-7313-4BDA-8880-461C5F007751} = {F355E45F-F54F-4B42-8916-9A633A392789}
{558479FB-A397-4EE9-A1AD-879F80D1FCD0} = {F355E45F-F54F-4B42-8916-9A633A392789} {3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7} = {F355E45F-F54F-4B42-8916-9A633A392789}
{3C532D80-32B4-40E5-B5FE-BC6BAE1A00E7} = {558479FB-A397-4EE9-A1AD-879F80D1FCD0}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

4
src/AddIns/Analysis/CodeQuality/CodeQuality.csproj

@ -106,6 +106,10 @@
<Name>Mono.Cecil</Name> <Name>Mono.Cecil</Name>
<Private>False</Private> <Private>False</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name> <Name>ICSharpCode.NRefactory</Name>

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

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reflection;
using ICSharpCode.CodeQuality.Engine.Dom; using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -18,13 +17,14 @@ namespace ICSharpCode.CodeQuality.Engine
/// </summary> /// </summary>
public class AssemblyAnalyzer public class AssemblyAnalyzer
{ {
CecilLoader loader = new CecilLoader(true); CecilLoader loader = new CecilLoader(true) { IncludeInternalMembers = true };
ICompilation compilation; ICompilation compilation;
Dictionary<IAssembly, AssemblyNode> assemblyMappings; internal Dictionary<IAssembly, AssemblyNode> assemblyMappings;
Dictionary<string, NamespaceNode> namespaceMappings; internal Dictionary<string, NamespaceNode> namespaceMappings;
Dictionary<ITypeDefinition, TypeNode> typeMappings; internal Dictionary<ITypeDefinition, TypeNode> typeMappings;
Dictionary<IMethod, MethodNode> methodMappings; internal Dictionary<IMethod, MethodNode> methodMappings;
Dictionary<IField, FieldNode> fieldMappings; internal Dictionary<IField, FieldNode> fieldMappings;
internal Dictionary<MemberReference, IEntity> cecilMappings;
List<string> fileNames; List<string> fileNames;
public AssemblyAnalyzer() public AssemblyAnalyzer()
@ -45,25 +45,54 @@ namespace ICSharpCode.CodeQuality.Engine
assemblyMappings = new Dictionary<IAssembly, AssemblyNode>(); assemblyMappings = new Dictionary<IAssembly, AssemblyNode>();
namespaceMappings = new Dictionary<string, NamespaceNode>(); namespaceMappings = new Dictionary<string, NamespaceNode>();
typeMappings = new Dictionary<ITypeDefinition, TypeNode>(); typeMappings = new Dictionary<ITypeDefinition, TypeNode>();
fieldMappings = new Dictionary<IField, FieldNode>();
methodMappings = new Dictionary<IMethod, MethodNode>();
cecilMappings = new Dictionary<MemberReference, IEntity>();
foreach (var type in compilation.GetAllTypeDefinitions()) { foreach (var type in compilation.GetAllTypeDefinitions()) {
AnalyzeType(type); ReadType(type);
}
foreach (TypeNode type in typeMappings.Values) {
foreach (var field in type.TypeDefinition.Fields) {
var node = new FieldNode(field);
fieldMappings.Add(field, node);
try {
var cecilObj = loader.GetCecilObject((IUnresolvedField)field.UnresolvedMember);
cecilMappings[cecilObj] = field;
} catch (InvalidOperationException) {}
type.Children.Add(node);
}
foreach (var method in type.TypeDefinition.Methods) {
var node = new MethodNode(method);
methodMappings.Add(method, node);
try {
var cecilObj = loader.GetCecilObject((IUnresolvedMethod)method.UnresolvedMember);
cecilMappings[cecilObj] = method;
} catch (InvalidOperationException) {}
type.Children.Add(node);
}
}
ILAnalyzer analyzer = new ILAnalyzer(loadedAssemblies.Select(asm => loader.GetCecilObject(asm)).ToArray(), this);
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) {}
} }
return new ReadOnlyCollection<AssemblyNode>(assemblyMappings.Values.ToList()); return new ReadOnlyCollection<AssemblyNode>(assemblyMappings.Values.ToList());
} }
IEnumerable<IUnresolvedAssembly> LoadAssemblies() IEnumerable<IUnresolvedAssembly> LoadAssemblies()
{ {
var resolver = new DefaultAssemblyResolver(); var resolver = new AssemblyResolver();
foreach (var file in fileNames) { List<AssemblyDefinition> assemblies = new List<AssemblyDefinition>();
var mainAsm = loader.LoadAssemblyFile(file); foreach (var file in fileNames.Distinct(StringComparer.OrdinalIgnoreCase))
yield return mainAsm; assemblies.Add(resolver.LoadAssemblyFile(file));
var referencedAssemblies = loader.GetCecilObject(mainAsm).Modules foreach (var asm in assemblies.ToArray())
.SelectMany(m => m.AssemblyReferences) assemblies.AddRange(asm.Modules.SelectMany(m => m.AssemblyReferences).Select(r => resolver.Resolve(r)));
.Select(r => resolver.Resolve(r)); return assemblies.Distinct().Select(asm => loader.LoadAssembly(asm));
foreach (var asm in referencedAssemblies)
yield return loader.LoadAssembly(asm);
}
} }
NamespaceNode GetOrCreateNamespace(AssemblyNode assembly, string namespaceName) NamespaceNode GetOrCreateNamespace(AssemblyNode assembly, string namespaceName)
@ -88,13 +117,31 @@ namespace ICSharpCode.CodeQuality.Engine
return result; return result;
} }
void AnalyzeType(ITypeDefinition type) void ReadType(ITypeDefinition type)
{ {
var asm = GetOrCreateAssembly(type.ParentAssembly); var asm = GetOrCreateAssembly(type.ParentAssembly);
var ns = GetOrCreateNamespace(asm, type.Namespace); var ns = GetOrCreateNamespace(asm, type.Namespace);
TypeNode parent;
var node = new TypeNode(type); var node = new TypeNode(type);
typeMappings.Add(type, node); if (type.DeclaringTypeDefinition != null) {
if (typeMappings.TryGetValue(type.DeclaringTypeDefinition, out parent))
parent.Children.Add(node);
else
throw new Exception("TypeNode not found: " + type.DeclaringTypeDefinition.FullName);
} else
ns.Children.Add(node); ns.Children.Add(node);
cecilMappings[loader.GetCecilObject(type.Parts.First())] = type;
typeMappings.Add(type, node);
}
class AssemblyResolver : DefaultAssemblyResolver
{
public AssemblyDefinition LoadAssemblyFile(string fileName)
{
var assembly = AssemblyDefinition.ReadAssembly(fileName, new ReaderParameters { AssemblyResolver = this });
RegisterAssembly(assembly);
return assembly;
}
} }
} }
} }

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

@ -3,7 +3,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.CodeQuality.Engine.Dom namespace ICSharpCode.CodeQuality.Engine.Dom
{ {
@ -27,21 +29,16 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
get { return namespaces; } get { return namespaces; }
} }
public IEnumerable<INode> Uses { public IEnumerable<INode> Descendants {
get { get { return TreeTraversal.PreOrder(Children, node => node.Children); }
throw new NotImplementedException();
}
} }
public IEnumerable<INode> UsedBy { public IEnumerable<INode> Uses {
get { get { return Descendants.SelectMany(node => node.Uses); }
throw new NotImplementedException();
}
} }
public void CalculateMetricsAndFreeze(IEnumerable<AssemblyNode> assemblies) public IEnumerable<INode> UsedBy {
{ get { return Descendants.SelectMany(node => node.UsedBy); }
} }
public Relationship GetRelationship(INode value) public Relationship GetRelationship(INode value)
@ -49,6 +46,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
Relationship r = new Relationship(); Relationship r = new Relationship();
if (value == this) if (value == this)
r.AddRelationship(RelationshipType.Same); 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; return r;
} }
} }

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

@ -3,6 +3,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom namespace ICSharpCode.CodeQuality.Engine.Dom
@ -16,9 +18,7 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
} }
public IList<INode> Children { public IList<INode> Children {
get { get { return null; }
throw new NotImplementedException();
}
} }
public IEnumerable<INode> Uses { public IEnumerable<INode> Uses {
@ -38,6 +38,10 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
Relationship r = new Relationship(); Relationship r = new Relationship();
if (value == this) if (value == this)
r.AddRelationship(RelationshipType.Same); r.AddRelationship(RelationshipType.Same);
if (Uses.Contains(value))
r.AddRelationship(RelationshipType.Uses);
if (UsedBy.Contains(value))
r.AddRelationship(RelationshipType.UsedBy);
return r; return r;
} }
} }

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

@ -3,34 +3,34 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.CodeQuality.Engine.Dom namespace ICSharpCode.CodeQuality.Engine.Dom
{ {
public class FieldNode : INode public class FieldNode : INode
{ {
public string Name { public IField FieldDefinition { get; private set; }
get {
throw new NotImplementedException(); public FieldNode(IField fieldDefinition)
{
this.FieldDefinition = fieldDefinition;
} }
public string Name {
get { return FieldDefinition.PrintFullName(); }
} }
public IList<INode> Children { public IList<INode> Children {
get { get { return null; }
throw new NotImplementedException();
}
} }
public IEnumerable<INode> Uses { public IEnumerable<INode> Uses {
get { get { return Enumerable.Empty<INode>(); }
throw new NotImplementedException();
}
} }
public IEnumerable<INode> UsedBy { public IEnumerable<INode> UsedBy {
get { get { return Enumerable.Empty<INode>(); }
throw new NotImplementedException();
}
} }
public Relationship GetRelationship(INode value) public Relationship GetRelationship(INode value)

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

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

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

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.CodeQuality.Engine.Dom namespace ICSharpCode.CodeQuality.Engine.Dom
{ {
@ -25,16 +26,16 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
get { return types; } get { return types; }
} }
public IEnumerable<INode> Uses { public IEnumerable<INode> Descendants {
get { get { return TreeTraversal.PreOrder(Children, node => node.Children); }
throw new NotImplementedException();
} }
public IEnumerable<INode> Uses {
get { return Descendants.SelectMany(node => node.Uses); }
} }
public IEnumerable<INode> UsedBy { public IEnumerable<INode> UsedBy {
get { get { return Descendants.SelectMany(node => node.UsedBy); }
throw new NotImplementedException();
}
} }
public Relationship GetRelationship(INode value) public Relationship GetRelationship(INode value)
@ -42,6 +43,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
Relationship r = new Relationship(); Relationship r = new Relationship();
if (value == this) if (value == this)
r.AddRelationship(RelationshipType.Same); 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; return r;
} }
} }

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

@ -16,9 +16,7 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
} }
public IList<INode> Children { public IList<INode> Children {
get { get { return null; }
throw new NotImplementedException();
}
} }
public IEnumerable<INode> Uses { public IEnumerable<INode> Uses {

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

@ -30,7 +30,7 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
public void AddRelationship(RelationshipType type) public void AddRelationship(RelationshipType type)
{ {
if (type == RelationshipType.UseThis || type == RelationshipType.UsedBy) if (type == RelationshipType.Uses || type == RelationshipType.UsedBy)
OccurrenceCount++; OccurrenceCount++;
Relationships.Add(type); Relationships.Add(type);
@ -48,13 +48,30 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
} }
} }
/// <summary>
/// Type of relationship between two INodes.
/// </summary>
public enum RelationshipType public enum RelationshipType
{ {
OneWayTo, /// <summary>
UseThis, /// a and b are not related to each other.
UsedBy, /// </summary>
Same, None,
/// <summary>
/// a contains b.
/// </summary>
Contains, Contains,
None /// <summary>
/// a uses b.
/// </summary>
Uses,
/// <summary>
/// a is used by b.
/// </summary>
UsedBy,
/// <summary>
/// a and b are the same INode
/// </summary>
Same
} }
} }

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

@ -3,7 +3,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.CodeQuality.Engine.Dom namespace ICSharpCode.CodeQuality.Engine.Dom
{ {
@ -14,28 +17,29 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
public TypeNode(ITypeDefinition typeDefinition) public TypeNode(ITypeDefinition typeDefinition)
{ {
this.TypeDefinition = typeDefinition; this.TypeDefinition = typeDefinition;
children = new List<INode>();
} }
public string Name { public string Name {
get { return TypeDefinition.Name; } get { return TypeDefinition.Name; }
} }
List<INode> children;
public IList<INode> Children { public IList<INode> Children {
get { get { return children; }
return new List<INode>();
} }
public IEnumerable<INode> Descendants {
get { return TreeTraversal.PreOrder(Children, node => node.Children); }
} }
public IEnumerable<INode> Uses { public IEnumerable<INode> Uses {
get { get { return Descendants.SelectMany(node => node.Uses); }
throw new NotImplementedException();
}
} }
public IEnumerable<INode> UsedBy { public IEnumerable<INode> UsedBy {
get { get { return Descendants.SelectMany(node => node.UsedBy); }
throw new NotImplementedException();
}
} }
public Relationship GetRelationship(INode value) public Relationship GetRelationship(INode value)
@ -43,6 +47,12 @@ namespace ICSharpCode.CodeQuality.Engine.Dom
Relationship r = new Relationship(); Relationship r = new Relationship();
if (value == this) if (value == this)
r.AddRelationship(RelationshipType.Same); 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; return r;
} }
} }

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

@ -2,6 +2,12 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.CodeQuality.Engine namespace ICSharpCode.CodeQuality.Engine
{ {
@ -10,8 +16,72 @@ namespace ICSharpCode.CodeQuality.Engine
/// </summary> /// </summary>
public class ILAnalyzer public class ILAnalyzer
{ {
public ILAnalyzer() AssemblyDefinition[] assemblies;
AssemblyAnalyzer mappings;
public ILAnalyzer(AssemblyDefinition[] assemblies, AssemblyAnalyzer mappings)
{
if (assemblies == null)
throw new ArgumentNullException("assemblies");
this.assemblies = assemblies;
this.mappings = mappings;
}
public void Analyze(MethodBody body, MethodNode analyzedMethod, out int cyclomaticComplexity)
{ {
cyclomaticComplexity = 0;
if (body == null)
return;
foreach (var instruction in body.Instructions) {
// IL cyclomatic complexity
if (instruction.OpCode.FlowControl == FlowControl.Cond_Branch)
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 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);
// }
// }
}
}
public object ReadOperand(Instruction instruction)
{
while (instruction.Operand is Instruction)
instruction = (Instruction)instruction.Operand;
return instruction.Operand;
} }
} }
} }

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

@ -22,7 +22,7 @@ namespace ICSharpCode.CodeQuality.Gui
// add other way // add other way
foreach (var relationship in fromRelationship.Relationships) { foreach (var relationship in fromRelationship.Relationships) {
if (relationship == RelationshipType.UseThis) if (relationship == RelationshipType.Uses)
toRelationship.AddRelationship(RelationshipType.UsedBy); toRelationship.AddRelationship(RelationshipType.UsedBy);
} }

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

@ -70,7 +70,7 @@
Grid.Row="2" Grid.Column="2" Grid.Row="2" Grid.Column="2"
CanContentScroll="True" CanContentScroll="True"
ScrollChanged="ViewScrollChanged"> ScrollChanged="ViewScrollChanged">
<gui:DependencyMatrixControl x:Name="matrix" HoveredCellChanged="MatrixHoveredCellChanged"/> <gui:DependencyMatrixControl x:Name="matrix" HoveredCellChanged="MatrixHoveredCellChanged" MouseMove="MatrixMouseMove" MouseLeave="MatrixMouseLeave" />
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>

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

@ -15,7 +15,6 @@ using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Shapes; using System.Windows.Shapes;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.CodeQuality; using ICSharpCode.CodeQuality;
using ICSharpCode.CodeQuality.Engine.Dom; using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
@ -30,6 +29,7 @@ namespace ICSharpCode.CodeQuality.Gui
{ {
ScrollViewer topTreeScrollViewer, leftTreeScrollViewer; ScrollViewer topTreeScrollViewer, leftTreeScrollViewer;
NodeDescriptionViewModel nodeDescriptionViewModel; NodeDescriptionViewModel nodeDescriptionViewModel;
ToolTip infoTooltip;
public DependencyMatrixView() public DependencyMatrixView()
{ {
@ -44,6 +44,7 @@ namespace ICSharpCode.CodeQuality.Gui
matrix.Colorizer = new DependencyColorizer(); matrix.Colorizer = new DependencyColorizer();
matrix.ScrollOwner = scrollViewer; matrix.ScrollOwner = scrollViewer;
infoTooltip = new ToolTip() { StaysOpen = false };
} }
@ -64,6 +65,7 @@ namespace ICSharpCode.CodeQuality.Gui
topCol.CollectionChanged += BuildTopINodeList; topCol.CollectionChanged += BuildTopINodeList;
var matrix = new DependencyMatrix(); var matrix = new DependencyMatrix();
if (nodes != null)
AddChildrenToMatrix(matrix, nodes); AddChildrenToMatrix(matrix, nodes);
this.matrix.Matrix = matrix; this.matrix.Matrix = matrix;
BuildLeftINodeList(null, null); BuildLeftINodeList(null, null);
@ -76,6 +78,7 @@ namespace ICSharpCode.CodeQuality.Gui
foreach (var node in nodes) { foreach (var node in nodes) {
matrix.AddColumn(node); matrix.AddColumn(node);
matrix.AddRow(node); matrix.AddRow(node);
if (node.Children != null)
AddChildrenToMatrix(matrix, node.Children); AddChildrenToMatrix(matrix, node.Children);
} }
} }
@ -145,6 +148,7 @@ namespace ICSharpCode.CodeQuality.Gui
matrix.HighlightLine(HeaderType.Rows, n.Node); matrix.HighlightLine(HeaderType.Rows, n.Node);
leftTree.SelectedItem = n; leftTree.SelectedItem = n;
} }
infoTooltip.IsOpen = false;
} }
void TopTreeMouseMove(object sender, System.Windows.Input.MouseEventArgs e) void TopTreeMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
@ -155,6 +159,7 @@ namespace ICSharpCode.CodeQuality.Gui
matrix.HighlightLine(HeaderType.Columns, n.Node); matrix.HighlightLine(HeaderType.Columns, n.Node);
topTree.SelectedItem = n; topTree.SelectedItem = n;
} }
infoTooltip.IsOpen = false;
} }
MatrixTreeNode ConvertNode(DependencyObject node) MatrixTreeNode ConvertNode(DependencyObject node)
@ -175,6 +180,32 @@ namespace ICSharpCode.CodeQuality.Gui
topTree.SelectedItem = topTree.Items[e.HoveredCell.ColumnIndex + 1]; topTree.SelectedItem = topTree.Items[e.HoveredCell.ColumnIndex + 1];
} }
} }
void MatrixMouseMove(object sender, MouseEventArgs e)
{
infoTooltip.Placement = PlacementMode.Relative;
infoTooltip.VerticalOffset = 15;
infoTooltip.PlacementTarget = this;
infoTooltip.Content = GetTooltip(matrix.HoveredCell.Value);
infoTooltip.IsOpen = true;
}
object GetTooltip(Relationship relationship)
{
string text = "is not related to";
if (relationship.Relationships.Any(r => r == RelationshipType.Uses))
text = "uses";
else if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy))
text = "is used by";
else if (relationship.Relationships.Any(r => r == RelationshipType.Same))
text = "is the same as";
return string.Format("{0} {1} {2}", relationship.From.Name, text, relationship.To.Name);
}
void MatrixMouseLeave(object sender, MouseEventArgs e)
{
infoTooltip.IsOpen = false;
}
#endregion #endregion
} }
} }

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

@ -15,7 +15,7 @@ namespace ICSharpCode.CodeQuality.Gui
public static class NodeIconService public static class NodeIconService
{ {
static readonly BitmapSource NamespaceNode = GetImage("Icons.16x16.NameSpace"); static readonly BitmapSource NamespaceNode = GetImage("Icons.16x16.NameSpace");
static readonly BitmapSource Assembly = GetImage("Icons.16x16.Assembly"); static readonly BitmapSource Assembly = GetImage("Icons.16x16.Reference");
static readonly BitmapSource Class = GetImage("Icons.16x16.Class"); static readonly BitmapSource Class = GetImage("Icons.16x16.Class");
static readonly BitmapSource InternalClass = GetImage("Icons.16x16.InternalClass"); static readonly BitmapSource InternalClass = GetImage("Icons.16x16.InternalClass");

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

@ -41,10 +41,10 @@ namespace ICSharpCode.CodeQuality
if (relationship == null) if (relationship == null)
return Colors.Transparent; return Colors.Transparent;
if (relationship.Relationships.Any(r => r == RelationshipType.UseThis)) if (relationship.Relationships.Any(r => r == RelationshipType.Uses))
return Colors.LightBlue; return Colors.LightGreen;
if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy)) if (relationship.Relationships.Any(r => r == RelationshipType.UsedBy))
return Colors.Violet; return Colors.LightBlue;
if (relationship.Relationships.Any(r => r == RelationshipType.Same)) if (relationship.Relationships.Any(r => r == RelationshipType.Same))
return Colors.Gray; return Colors.Gray;

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

@ -6,9 +6,10 @@ using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.CodeQuality.Engine.Dom; using ICSharpCode.CodeQuality.Engine.Dom;
using ICSharpCode.CodeQuality.Gui; using ICSharpCode.CodeQuality.Gui;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.CodeQuality namespace ICSharpCode.CodeQuality
@ -21,6 +22,7 @@ namespace ICSharpCode.CodeQuality
public static void FillTree(SharpTreeView tree, IEnumerable<INode> rootNodes) public static void FillTree(SharpTreeView tree, IEnumerable<INode> rootNodes)
{ {
tree.Root = new SharpTreeNode(); tree.Root = new SharpTreeNode();
if (rootNodes != null)
CreateItems(rootNodes, tree.Root); CreateItems(rootNodes, tree.Root);
} }
@ -29,6 +31,7 @@ namespace ICSharpCode.CodeQuality
foreach (INode node in nodes) { foreach (INode node in nodes) {
var item = new MatrixTreeNode(node); var item = new MatrixTreeNode(node);
parent.Children.Add(item); parent.Children.Add(item);
if (node.Children != null)
CreateItems(node.Children, item); CreateItems(node.Children, item);
} }
} }
@ -73,5 +76,12 @@ namespace ICSharpCode.CodeQuality
(byte)(c1.G * amountFrom + c2.G * percent), (byte)(c1.G * amountFrom + c2.G * percent),
(byte)(c1.B * amountFrom + c2.B * percent)); (byte)(c1.B * amountFrom + c2.B * percent));
} }
static readonly IAmbience amb = new CSharpAmbience() { ConversionFlags = ConversionFlags.ShowParameterList | ConversionFlags.ShowParameterNames | ConversionFlags.ShowReturnType | ConversionFlags.ShowTypeParameterList };
public static string PrintFullName(this IEntity entity)
{
return amb.ConvertEntity(entity);
}
} }
} }

20
src/AddIns/Analysis/CodeQuality/Utils/Utils.cs

@ -2,8 +2,11 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Mono.Cecil;
namespace ICSharpCode.CodeQuality namespace ICSharpCode.CodeQuality
{ {
/// <summary> /// <summary>
@ -14,4 +17,21 @@ namespace ICSharpCode.CodeQuality
[DllImport("gdi32.dll")] [DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject); public static extern bool DeleteObject(IntPtr hObject);
} }
public class AssemblyNameReferenceComparer : IEqualityComparer<AssemblyNameReference>
{
public bool Equals(AssemblyNameReference x, AssemblyNameReference y)
{
if (x == y) return true;
if (x != null && y != null)
return x.FullName == y.FullName;
return false;
}
public int GetHashCode(AssemblyNameReference obj)
{
if (obj == null) return 0;
return obj.FullName.GetHashCode();
}
}
} }

Loading…
Cancel
Save